Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Delraich en 5 Julio 2010, 23:57 pm



Título: Leer de la entrada estandar linea por linea
Publicado por: Delraich en 5 Julio 2010, 23:57 pm
Primero q nada hola a todos, empece hace poco a programar en C.. Lo q mas me interesa es programar algoritmos de matematica discreta, y tengo problemas con uno q calcula MaxFlow en un grafo.. con el algoritmo en si no, sino con la entrada estandar.. Quiero q lea desde la entrada estandar, cosas de la siguiente manera:
a b c
donde a, b y c son enteros... Pero quiero q lea mientras una linea sea de ese tipo.. cuando llega algo q no es de ese formato, deberia dejar de leer en la entrada estandar.. entonces para q quede claro, deberia poder poner por ejemplo:
1 2 3
3 2 5
4 5 2
3

En este ejemplo, quiero q tome el 1 2 3, el 3 2 5, el 4 5 2 y q deje de leer cuando vea q la 4ta linea tiene un solo numero...

Otro ejemplo seria
1 2 3
4 5 6
2 4 5 6

Aqui deberia leer 2 lineas, y cortar cuando llega la 3ra porq tiene un entero de mas..
Y tambien tiene q cortar si llega algo asi:

1 2 3
3 4 5
hola

Lee 2 lineas, y luego corta porq llega algo q no tiene nada q ver con el formato...

Probe con scanf pero no logro q corte cuando la linea tiene caracteres de menos.. ya q el scanf se queda esperando a q se completen sus parametros...\
Por otro lado tampoco logro q corte cuando llegan caracteres de mas, ya q los guarda en el buffer para el siguiente scanf...

Asi q si me pueden ayudar, desde ya les agradezco


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: nicolas_cof en 6 Julio 2010, 00:45 am
Delraich, bienvenido! te recomendaria leer las Reglas del subforo (https://foro.elhacker.net/programacion_cc/reglas_del_subforo-t251603.0.html)

Si pones algo del avance que llevas hecho seria mas facil para nosotros poder ayudarte.

Te invito a que pases por estos temas...

https://foro.elhacker.net/programacion_cc/librospapers_c_and_c-t296234.0.html

https://foro.elhacker.net/programacion_cc/lo_que_no_hay_que_hacer_en_cc_nivel_basico-t277729.0.html

Salu10.


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: Littlehorse en 6 Julio 2010, 00:46 am
Podrías hacer un arreglo de cadenas e ir leyendo linea a linea, luego convertir los datos relevantes para poder operarlos. Podrías también leer una cadena con toda la expresión, para luego poder tomar los datos relevantes de dicha expresión, convertirlos y operarlos.

Pon el código que llevas hecho a ver si podemos partir de ahí para ayudarte.

Saludos


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: ghastlyX en 6 Julio 2010, 00:56 am
Puedes leer una línea entera usando
Código
  1. getline(cin,s);
Donde s es una string.

Luego para parsear la entrada, si sabes que siempre serán números, puedes usar stringstream e ir leyendo desde s y añadiendo en un vector los números. Si no, deberías picar alguna función que compruebe que si es número o no.

En referencia al algoritmo, ¿cuál usas para calcular el Maxflow?


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: Delraich en 6 Julio 2010, 01:03 am
Antes q nada, muchas gracias por responder tan rapido...

El programa la verdad es bastante extenso, sobre todo la parte del algoritmo en si.. pero la parte q lee desde la entrada estandar seria algo asi :

Ya cree la estructura donde voy a guardar el network (grafo).. y ahora tengo q agregar lado por lado... esta funcion está en un ciclo.. el ciclo corta cuando el valor de esta funcion es 0.. por eso, esta funcion debe devolver 1 mientras la entrada estandar sea del formato q quiero, y 0 cuando no sea..
La funcion CargarLado se encarga de tomar los 3 enteros (q serian vertice 1 del lado, vertice 2 del lado y capacidad de ese lado) y los introduce en la esctructura del grafo.. si puede cargarlos bien, devuelve 1.. sino, devuelve 0.. El problema aca es q cuando introduzco algo por entrada estandar q tiene caracteres, pero menos de 3 o mas de 3, el programa no corta.. sino q se queda esperando.. yo necesitaria que tome la linea entera como dice Littlehorse, pero la verdad no se como hacerlo

Código
  1. int LeerLado (EstadoNetwork n) {
  2.  
  3.    res = scanf(" %u %u %u", &c1, &c2, &c3);
  4.  
  5.  if (res == 3)
  6.  {
  7.    res = CargarLado(n->network,c1,c2,c3);
  8.  }
  9.  else
  10.  {
  11.    res = 0;
  12.  }
  13.  return res;
  14. }
  15.  

Recien leo la respuesta de ghastlyx, voy a intentar hacerlo asi, pasa q no siempre van a ser numeros, asi q voy a tener q primero ver si son numeros, y si lo son ver si son la cantidad q necesito..
Estoy implementando el algoritmo de Dinic, con el paso bloqueante tambien de dinic..
Luego quizas intente wave, pero necesito poder ingresar los datos del grafo bien primero



Título: Re: Leer de la entrada estandar linea por linea
Publicado por: Littlehorse en 6 Julio 2010, 01:06 am
El problema es que lo te menciono ghastlyX  es C++, y según mencionas vos en el post inicial, estas codificando el algoritmo en C.

Declara una cadena, y léela con fgets, luego puedes parsear los datos y operarlos previa validación.

Saludos


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: ghastlyX en 6 Julio 2010, 01:14 am
No me había fijado que había puesto C, sin STL lo que he dicho como que no xDD.

Por si te sirve de ayuda, te dejo un código del algoritmo de Dinic que tenía hecho, sigue el formato de entrada y salida de este problema:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=10&page=show_problem&problem=761

Código
  1. /****************************************************************************************/
  2. /* Algoritmo Dinic (usa blocking flows en lugar de caminos aumentativos) Coste: O(V^2E) */
  3. /****************************************************************************************/
  4.  
  5. #include <iostream>
  6. #include <string.h>
  7. using namespace std;
  8.  
  9. //Cambiar constantes si es necesario
  10. #define NODOS 100
  11. const int INF = 1000000000;
  12.  
  13. int adj[NODOS][NODOS], deg[NODOS], cap[NODOS][NODOS], padre[NODOS], f[NODOS][NODOS], MC[NODOS], visto[NODOS];
  14. int n, m; // n = |V|, m = |E|
  15.  
  16. int Q[NODOS]; //cola
  17. int ebp, esp;
  18.  
  19. bool bfs(int s, int t) {
  20.    esp = ebp = 0;
  21.    memset(padre, -1, sizeof(padre));
  22.    memset(visto, 0, sizeof(visto));
  23.    visto[s] = 1;
  24.    padre[s] = -2;
  25.    Q[esp++] = s;
  26.    while (ebp != esp) {
  27.        int u = Q[ebp++];
  28.        for (int i = 0; i < deg[u]; ++i) {
  29.            int v = adj[u][i];
  30.            if (cap[u][v] - f[u][v] > 0 and not visto[v]) {
  31.                visto[v] = 1;
  32.                padre[v] = u;
  33.                Q[esp++] = v;
  34.            }
  35.        }
  36.    }
  37.    return visto[t];
  38. }
  39.  
  40. void mincut(int s) {
  41.    ebp = esp = 0;
  42.    Q[esp++] = s;
  43.    MC[s] = 1;
  44.    while (ebp != esp) {
  45.        int u = Q[ebp++];
  46.        for (int i = 0; i < deg[u]; ++i) {
  47.            int v = adj[u][i];
  48.            if (cap[u][v] - f[u][v] > 0 and not MC[v]) {
  49.                MC[v] = 1;
  50.                Q[esp++] = v;
  51.            }
  52.        }
  53.    }
  54. }
  55.  
  56. int maxflow(int s, int t) {
  57.    int flow = 0;
  58.    memset(MC, 0, sizeof(MC));
  59.    memset(f, 0, sizeof(f));
  60.    while (bfs(s, t)) {
  61.        for (int i = 0; i < n; ++i) {
  62.            if (cap[i][t] - f[i][t] > 0 and padre[i] != -1) {
  63.                int bot = cap[i][t] - f[i][t];
  64.                for (int v = i, u = padre[i]; u >= 0; v = u, u = padre[u])
  65.                    bot = min(bot, cap[u][v] - f[u][v]);
  66.                if (bot == 0) continue;
  67.                f[i][t] += bot;
  68.                f[t][i] -= bot;
  69.                for (int v = i, u = padre[i]; u >= 0; v = u, u = padre[u]) {
  70.                    f[u][v] += bot;
  71.                    f[v][u] -= bot;
  72.                }
  73.                flow += bot;
  74.            }
  75.        }
  76.    }
  77.    mincut(s); //MC[u] == 1 <=> u esta en la particion de s
  78.    return flow;
  79. }
  80.  
  81. int main() {
  82.    int net = 1;
  83.    while (cin >> n and n > 0) {
  84.        memset(deg, 0, sizeof(deg));
  85.        memset(cap, 0, sizeof(cap));
  86.        int s, t;
  87.        cin >> s >> t >> m;
  88.        s--; t--;
  89.        for (int i = 0; i < m; ++i) {
  90.            int a, b, c;
  91.            cin >> a >> b >> c;
  92.            --a; --b;
  93.            if (cap[a][b] == 0) {
  94.                adj[a][deg[a]++] = b;
  95.                adj[b][deg[b]++] = a;
  96.            }
  97.            cap[a][b] += c;
  98.            cap[b][a] += c;
  99.        }
  100.        cout << "Network " << net++ << endl;
  101.        cout << "The bandwidth is " << maxflow(s,t) << "." << endl << endl;
  102.    }
  103. }


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: do-while en 6 Julio 2010, 01:31 am
¡Buenas!

para poder leer linea por linea puedes declarar una vector de caracteres de dimension "algo grande", y leerlo con fgtes:
Código
  1. #define LINEA_MAX 256
  2.  
  3. char linea[LINEA_MAX];
  4.  
  5. /* leemos mientras quede informacion -> mientras linea[strlen(linea)]!='\n'
  6. ya que fgets obtiene informacion hasta (MAX_LINEA - 1) o hasta que encuentra un salto de
  7. linea (lo almacena como ultimo caracter de la cadena) o hasta que encuentra un EOF */
  8. do{
  9.    fgets(linea,LINEA_MAX,stdin);
  10.    /* y ahora con la informacion haces lo que quieras.
  11.     RECOMENDACION: usa strtok para obtener las distintas partes separadas por espacios */
  12. }while(linea[strlen(linea) - 1] != '\n'); /* Al ser '\n' el ultimo caracter, ya no queda nada en la entrada */
  13.  

El resto te lo dejo a ti. Tendras que estudiar las funciones de manejo de cadenas de stringh, de stdlibh, y seguramente tambien las de stdio.h.

¡Saludos!


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: Delraich en 6 Julio 2010, 01:38 am
De nuevo gracias por la ayuda, ya me voy a tomar un tiempo y leer el algoritmo q posteaste ghasltyx, ahora voy a intentar tomar linea por linea como me recomendaron, y ver como parseo la info... luego les cuento q tal me fue


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: MIG80 en 6 Julio 2010, 01:54 am
Bueno...talvez esto te solucione el problema con la entrada...

Código:
int leer3ent(int *c1,int *c2,int *c3)
{
  int res;
  char remanente[1000],lineaentrada[1000];
  
  fgets(lineaentrada,1000,stdin);
  fflush(stdin);
  res=sscanf(lineaentrada,"%u %u %u%s",c1,c2,c3,remanente);
  return (res==3)?1:0;
}

int LeerLado(EstadoNetwork n)
{
  res=leer3ent(&c1,&c2,&c3);
  if(res)
    res=CargarLado(n->network,c1,c2,c3);
  return res;
}

Saludos.


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: Delraich en 6 Julio 2010, 02:18 am
Muchas gracias czealt, eso es justamente lo q necesitaba! xD.. De nuevo muchas gracias a todos, y espero dentro de poco poder ayudarlos yo a ustedes


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: Littlehorse en 6 Julio 2010, 03:14 am
czealt, recuerda que utilizar fflush con stdin invoca comportamiento indefinido.

Saludos


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: misterharry en 6 Julio 2010, 04:10 am
czealt, recuerda que utilizar fflush con stdin invoca comportamiento indefinido.

Saludos

D: porque??? que es lo que hace para inestabilizar el comportamiento???
perdon la ignarancia pero me llama la atencion esto


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: do-while en 6 Julio 2010, 04:27 am
Aqui (http://foro.elhacker.net/programacion_cc/lo_que_no_hay_que_hacer_en_cc_nivel_basico-t277729.0.html) explica porque hay que utilizar fflush con sdtin, y otras muchas cosas que pueden dar problemas si no se manejan con cuidado.

¡Saludos!


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: misterharry en 6 Julio 2010, 04:44 am
jaja justo venia desde ese post (y muchos mas) donde esplican porke no debe usarse

gracias de todos modos. :D

bueno, jamas habia usado fflush para algo distinto de vaciar stdin. de hecho pense que para eso era..
no entiendo bien para que se ocupa reamlmete, visite cconclase para salir de la duda pero quede peor xD
onda, por un post lei que era para forzar la escritura y no para liberarla o algo asi :S


Título: Re: Leer de la entrada estandar linea por linea
Publicado por: MIG80 en 6 Julio 2010, 19:53 pm
czealt, recuerda que utilizar fflush con stdin invoca comportamiento indefinido.

Saludos

Bueno, reemplazando la línea fflush(stdin), el código corregido seria:

Código:
int leer3ent(int *c1,int *c2,int *c3)
{
  int res,lon_ent;
  char remanente[1000],lineaentrada[1000];
  
  fgets(lineaentrada,1000,stdin);
  lon_ent=strlen(lineaentrada);
  if(lon_ent)
  {
    if(lineaentrada[lon_ent-1]!='\n')
    {
      while(getchar()!='\n')
      ;
    }
  }
  res=sscanf(lineaentrada,"%u %u %u%s",c1,c2,c3,remanente);
  return (res==3)?1:0;
}

int LeerLado(EstadoNetwork n)
{
  res=leer3ent(&c1,&c2,&c3);
  if(res==3)
    res=CargarLado(n->network,c1,c2,c3);
  else
    res=0;
  return res;
}


a partir de ahora recordare no usar fflush(stdin), gracias por la información.

Saludos.