• 第一场个人图论专题


    http://poj.org/problem?id=1062

    枚举层次求最短路,比如酋长等级是5,m是2,那么就要枚举等级在3-5, 4-6, 5-7之间这三种情况的最短路里面的最小值了

    以前做过,不过这次做还是一直wa。。。原来是我在dijkstra初始化dist数组的时候出问题了。。弱爆了啊。。wa的真辛苦

    poj_1062
    #include<cstdio>
    #include<cstring>
    
    const int maxn = 110;
    int g[maxn][maxn];
    int dist[maxn], vis[maxn];
    int flag[maxn];
    int m, n;
    int cost[maxn], level[maxn];
    const int inf = 100000000;
    int dijk(){
        memset(vis, 0, sizeof vis);
        for(int i = 1; i <= n; i ++) if(flag[i] && g[1][i] != -1)dist[i] = g[1][i]; else dist[i] = inf;
        dist[1] = 0;
        vis[1] = 1;
        for(int i = 0; i < n - 1; i ++){
            int Min = inf, u;
            for(int j = 1; j <= n; j ++){
                if(!vis[j] && flag[j] && dist[j] < Min){
                    Min = dist[j];
                    u = j;
                }
            }
            if(Min == inf) break;
            vis[u] = 1;
            for(int j = 1;j <= n; j ++){
                if(!vis[j] &&  flag[j] && g[u][j] != -1 && dist[u] + g[u][j] < dist[j]){
                    dist[j] = dist[u] + g[u][j];
                }
            }
        }
        int ans = inf;
        for(int i = 1; i <= n; i ++){
            dist[i] += cost[i];
            if(dist[i] < ans)
              ans = dist[i];
        }
        //printf("dijk: %d\n", ans);
        return ans;
    }
    int main(){
        while(~scanf("%d%d", &m, &n)){
            memset(g, -1, sizeof g);
            for(int i = 1; i <= n; i ++){
                int p, l, x;
                scanf("%d%d%d", &p, &l, &x);
                cost[i] = p, level[i] = l;
                while(x --){
                    int t, v;
                    scanf("%d%d", &t, &v);
                    g[i][t] = v;
                }
            }
            int ans = inf;
            for(int i = 0; i <= m; i ++){
                memset(flag, 0, sizeof flag);
                for(int j = 1; j <= n; j ++)
                  if(level[j] >= level[1] - m + i && level[j] <= level[1] + i)
                    flag[j] = 1;
                int c = dijk();
                if(c < ans ) 
                  ans = c;
            }
            printf("%d\n", ans);
        }
        return 0;
    }

    http://poj.org/problem?id=1087

    给你一些现有的插座,然后给一些电器,这些电器必须用对应的插座,然后给一些转换器,可以把一些插座转换成另外的插座

    很明显的二分匹配,不过当时做的时候,一直在建图那一块出错。。。。最后的图是用floyd传递闭包之后再建图,很麻烦= =

    当然,这次也练习了下用网络流来解匹配的问题了,还是很好理解的

    poj_1087_maxmatch
    #include<cstdio>
    #include<cstring>
    
    
    const int maxn = 610;
    const int inf = 10000000;
    int g[maxn][maxn], gg[maxn][maxn];
    int link[maxn], vis[maxn];
    char str[maxn][30], plug[maxn][30];
    int cnt;
    int n, m, k;
    int find(char s[]){
        int i;
        for(i = 0; i < cnt; i ++){
            if(strcmp(s, str[i]) == 0) return i;
        }
        return i;
    }
    void init(){
        cnt = 0;
        memset(g, 0, sizeof g);
        memset(gg, 0, sizeof gg);
    }
    void build(){
        for(int i = 0; i < cnt; i ++){
            for(int j = 0; j < cnt; j ++){
                for(int k = 0; k < cnt; k ++){
                    //if(i == j || i == k) continue;
                    if(g[j][i] && g[i][k])
                      g[j][k] = 1;
                }
            }
        }
        memset(gg, 0, sizeof gg);
        for(int i = 0; i < m; i ++){
            int pos = find(plug[i]);
            gg[i][pos] = 1;
            for(int j = 0; j < n; j ++){
                if(g[pos][j])
                  gg[i][j] = 1;
            }
        }
    }
    int dfs(int u){
        for(int i = 0; i < n; i ++){
            if(!vis[i] && gg[u][i]){
                vis[i] = 1;
                if(link[i] == -1 || dfs(link[i])){
                    link[i] = u;
                    return 1;
                }
            }
        }
        return 0;
    }
    int maxmatch(){
        memset(link, -1, sizeof link);
        int ans = 0;
        for(int i = 0; i <m; i ++){
            memset(vis, 0, sizeof vis);
            if(dfs(i)) ans ++;
            //printf("ans:  %d\n", ans);
        }
        return ans;
    }
    int main(){
        scanf("%d", &n);
        init();
        for(int i = 0; i < n;i ++){
            char s[30];
            scanf("%s", s);
            strcpy(str[cnt], s);
            cnt++;
        }
        scanf("%d", &m);
        for(int i = 0; i < m;i ++){
            char s[30], ss[30];
            scanf("%s%s", s, ss);
            strcpy(plug[i], ss);
            int tmp = find(ss);
            if(tmp == cnt){
                strcpy(str[cnt], ss);
                cnt ++;
            }
            //g[i][tmp] = 1;
            //gg[i][tmp] = 1;
        }
        scanf("%d", &k);
        for(int i = 0; i < k; i ++){
            char s[30], ss[30];
            scanf("%s%s", s, ss);
            int a = find(s);
            if(a == cnt){
                strcpy(str[cnt], s);
                cnt ++;
                //a = cnt - 1;
            }    
            int b = find(ss);
            if(b == cnt){
                strcpy(str[cnt], ss);
                cnt ++;
                //b = cnt - 1;
            }
            g[a][b] = 1;
        }
        build();
        printf("%d\n", m - maxmatch());
        return 0;
    }
    poj_1087_maxflow
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<map>
    using namespace std;
    map <string, int> v;
    const int maxn(600);
    const int inf(10000000);
    int n, m, k;
    int s = 0, t = 1, cnt = 2;
    int c[maxn][maxn];
    int level[maxn], gap[maxn];
    int cur[maxn], pre[maxn];
    int sap(){
        int maxflow = 0;
        memset(level, 0, sizeof level);
        memset(gap, 0, sizeof gap);
        memset(cur, 0, sizeof cur);
        gap[s] = cnt;
        int aug = inf;
        int u = pre[s] = s, v;
        while(level[s] < cnt){
            for(v = cur[u]; v < cnt; v ++){
                if(c[u][v] && level[u] == level[v] + 1)
                  break;
            }
            //puts("--");
            if(v < cnt){
            //    puts("asdf");
                pre[v] = u;
                if(aug > c[u][v]) aug = c[u][v];
                u = cur[u] = v;
                if(u == t){
                    maxflow += aug;
                    for(v = t; v != s; v = pre[v]){
                        c[pre[v]][v] -= aug;
                        c[v][pre[v]] += aug;
                    }
                    aug = inf, u = s;
                }
            }else{
                int min_label = cnt;
                for(v = 0; v < cnt; v ++){
                    if(c[u][v] && min_label > level[v]){
                        min_label = level[v];
                        cur[u] = v;
                    }
                }
                if(--gap[level[u]] == 0)return maxflow;
                level[u] = min_label + 1;
                gap[level[u]] ++;
                u = pre[u];
            }
        }
        return maxflow;
    }
    int main(){
        scanf("%d", &n);
        for(int i = 0; i < n; i ++){
            string s;
            cin>>s;
            v[s] = cnt;
            c[cnt++][t] = 1;
        }
        scanf("%d", &m);
        for(int i = 0; i < m; i ++){
            string s1, s2;
            cin>>s1>>s2;
            v[s1] = cnt;
            c[s][cnt++] = 1;
            if(!v.count(s2))
              v[s2] = cnt ++;
            c[v[s1]][v[s2]] = 1;
        }
        scanf("%d", &k);
        for(int i = 0; i < k; i ++){
            string s1, s2;
            cin>>s1>>s2;
            if(!v.count(s1)) v[s1] = cnt ++;
            if(!v.count(s2)) v[s2] = cnt ++;
            c[v[s1]][v[s2]] = inf;
        }
        printf("%d\n", m - sap());
        return 0;
    }

    http://poj.org/problem?id=1094

    拓扑排序,题意有个trick啊。。。。我一直坑在这了。。还是看着解题报告想了好久才明白的

    其实是我没理解清,题目要求必须给出一个升序的,如果topsort的时候,有两个点可以选择,即这两个点不能确定拓扑关系。。就不能说确定的升序了。。。

    当然,这题也有用floyd做的。。我没研究。。

    poj_1094
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int g[30][30];
    int ind[30];
    int vis[30];
    char ans[30];
    int n, m;
    int sta[30];
    int pos;
    int topsort(){
         pos = 0;
    //    int top = -1;
        int ind1[30];
        for(int i = 0; i <= 26; i ++) ind1[i] = ind[i];
    //    for(int i = 0; i < n; i ++){
        //    if(vis[i] == 0) continue;
        //    if(ind1[i] == 0){
                //ind1[i] = top;
        //        top = i;
    //        }
    //    }
        int flag = 0;
        for(int i = 0; i < n; i ++){
        //    if(vis[i] == 0) continue;
        //    if(top == -1) return -1;
            int u = 0;
            int num = 0;
            for(int j = 0; j < n; j ++){
                if(ind1[j] == 0){
                    u = j;
                    num ++;
                }
            }
            if(num == 0)return -1;
            if(num > 1)//return -2;
            flag = 1;
            //top = ind1[top];
            ind1[u] = -1;
        //    sta[pos++] = u;
            pos += sprintf(ans + pos, "%c", u + 65);
            for(int j = 0; j < n; j ++){
            //    if(vis[j] == 0) continue;
                if(g[u][j]){
                //    if(--ind1[j] == 0){
                //        ind1[j] = top;
                //        top = j;
                    ind1[j] --;
                //    }
                }
            }
        }
        if(flag) return -2;
        ans[pos] = '\0';
        //sort(ans, ans + pos);
        return pos;
    }
    int main(){
        while(scanf("%d%d", &n, &m), n || m){
            memset(g, 0, sizeof g);
            memset(ind, 0, sizeof ind);
            memset(vis, 0, sizeof vis);
            int f = 0;
            for(int i = 1; i <= m; i ++){
                char s[10];;
                scanf("%s", s);
                int v = s[0] - 65, u = s[2] - 65;
                if(g[v][u])continue;
                g[v][u] = 1;
                ind[u] ++;
                vis[u] = vis[v] = 1;
                if(f) continue;
                int t = topsort();
                if(t == -1){
                    printf("Inconsistency found after %d relations.\n", i);
                    f = 1;
                }else if(t == n){
                    printf("Sorted sequence determined after %d relations: %s.\n", i,ans);
    //                for(int j = 0; j < pos; j ++)putchar(sta[j]+65);
    //                puts(".");
                        f = 1;
                }
            }
               if(!f)puts("Sorted sequence cannot be determined.");
        }
        return 0;
    }

    http://poj.org/problem?id=1112

    这是最后完成的一题。。。看着解题报告抄的。。。边抄边理解啊T_T我感觉我还是没理解透这题。。

    先求补图,然后求强连通,然后DP。。

    贴个代码吧。。

    poj_1112
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    const int maxn(128);
    bool map[maxn][maxn], tmp[maxn][maxn], vis[maxn], f[maxn][maxn];
    int c[maxn], a[maxn], b[maxn], st[maxn], l[maxn][maxn];
    int mind = maxn, s = 0, rt[maxn];
    int k1[maxn], k2[maxn];
    int lk1 = 0, lk2 = 0;
    int n, x, cnt;
    
    void init(){
        scanf("%d", &n);
        memset(tmp, false, sizeof tmp);
        for(int i = 1; i <= n; i ++){
            scanf("%d", &x);
            while(x != 0){
                tmp[i][x] = true;
                scanf("%d", &x);
            }
        }
        memset(map, false, sizeof map);
        for(int i = 1; i <= n; i ++){
            for(int j = i + 1; j <= n; j ++){
                if(!(tmp[i][j] && tmp[j][i])){
                    map[i][j] = map[j][i] = true;
                }
            }
        }
    }
    bool fill(int v, int color){
        c[v] = color;
        vis[v] = true;
        for(int i = 1; i <= n; i ++){
            if(map[v][i]){
                if(c[i] == color) return false;
                else if(c[i] == 0){
                    if(!fill(i, -color))
                      return false;
                }
            }
        }
        return true;
    }
    bool make(){
        memset(vis, false, sizeof vis);
        memset(c, 0, sizeof c);
        memset(a, 0, sizeof a);
        memset(b, 0, sizeof b);
        cnt = 0;
        for(int i = 1; i <= n; i ++){
            if(!vis[i]){
                if(!fill(i, i)) return false;
                cnt ++;
                for(int j = 1; j <= n; j ++){
                    a[cnt] += (c[j] == i);
                    b[cnt] += (c[j] == -i);
                }
                st[cnt] = i;
            }
        }
        return true;
    }
    int abs(int a){
        return a > 0 ? a : -a;
    }
    void dp(){
        memset(f, false, sizeof f);
        f[0][0] = 1;
        for(int i = 1; i <= cnt; i ++){
            for(int j = n; j >= 0; j --){
                for(int k = n; k >= 0; k --){
                    if(f[j][k]) continue;
                    if(j >= a[i] && k >= b[i]){
                        if(f[j - a[i]][k - b[i]]){
                            f[j][k] = true;
                            l[j][k] = i;
                        }
                    }
                    if(j >= b[i] && k >= a[i]){
                        if(f[j - b[i]][k - a[i]]){
                            f[j][k] = true;
                            l[j][k] = -i;
                        }
                    }
                }
            }
        }
    }
    void print(){
        memset(k1, 0, sizeof k1);
        memset(k2, 0, sizeof k2);
        lk1 = 0, lk2 = 0;
        for(int i = 1; i <= s; i ++){
            for(int j = 1; j <= n; j ++){
                if(rt[i] > 0){
                    if(c[j] == st[rt[i]]) k1[++lk1] = j;
                    if(c[j] == -st[rt[i]])k2[++lk2] = j;
                }else{
                    if(c[j] == -st[-rt[i]])k1[++lk1] = j;
                    if(c[j] == st[-rt[i]]) k2[++lk2] = j;
                }
            }
        }
        for(int i = 1; i < lk1; i ++){
            for(int j = i + 1; j <= lk1; j ++)
              if(k1[i] > k1[j])
                swap(k1[i], k1[j]);
        }
        for(int i = 1; i < lk2; i ++){
            for(int j = i + 1; j <= lk2; j ++)
              if(k2[i] > k2[j])
                swap(k2[i], k2[j]);
        }
        printf("%d", lk1);
        for(int i = 1; i <= lk1; i ++)
          printf(" %d", k1[i]);
        puts("");
        printf("%d", lk2);
        for(int i = 1; i <= lk2; i ++)
          printf(" %d", k2[i]);
        puts("");
    }
    void solve(){
        dp();
        mind = maxn;
        s = 0;
        memset(rt, 0, sizeof rt);
        for(int i = 0; i <= n; i ++){
            for(int j = 0; j <= n; j ++)
              if(f[i][j] && (i+j == n))
                mind = min(mind, abs(i-j));
        }
        for(int i = 0; i <= n; i ++)
          for(int j = 0; j <= n; j ++)
            if(f[i][j] && (i+j == n) && abs(i-j) == mind){
                int x = i, y = j, dx, dy;
                while(x + y){
                    rt[++s] = l[x][y];
                    if(l[x][y] > 0){
                        dx = a[l[x][y]];
                        dy = b[l[x][y]];
                    }else{
                        dx = b[abs(l[x][y])];
                        dy = a[abs(l[x][y])];
                    }
                    x -= dx;
                    y -= dy;
                }
                print();
                return;
            }
    }
    int main(){
        init();
        if(!make()) puts("No solution");
        else
          solve();
        return 0;
    }

    http://poj.org/problem?id=1125

    这题明显的题目理解难度大于题目难度啊。。

    不过这题好早做过。。。直接贴的代码。。太恶心

    poj_1125
    #include<cstdio>
    #include<cstring>
    
    int g[110][110];
    const int inf = 10000000;
    int main(){
        int n;
        while(scanf("%d", &n), n){
            for(int i = 1; i <= n; i ++){
                for(int j = 1; j <= n ;j ++){
                    if(i == j) g[i][j] = 0;
                    else
                      g[i][j] = inf;
                }
            }
            for(int i = 1; i <= n; i ++){
                int num;
                scanf("%d", &num);
                while(num --){
                    int id, time;
                    scanf("%d%d", &id, &time);
                    g[i][id] = time;
                }
            }
            for(int k = 1; k <= n; k ++){
                for(int i = 1; i <= n; i ++){
                    for(int j = 1; j <= n; j ++){
                        if(k == i || k == j) continue;
                        if(g[i][k] + g[k][j] < g[i][j])
                          g[i][j] = g[i][k] + g[k][j];
                    }
                }
            }
            int min = inf, max;
            int id;
            for(int i = 1; i <= n; i ++){
                max = 0;
                for(int j = 1;j <= n; j ++){
                    if(max < g[i][j])
                      max = g[i][j];
                }
                if(max < min){
                    id = i;
                    min = max;
                }
            }
            if(min == inf) puts("disjoint");else
            printf("%d %d\n", id, min);
        }
        return 0;
    }

    http://poj.org/problem?id=1135

    就是骨牌,倒,然后求最后倒的地方和时间

    最短路= =畸形的

    如果是一个点的话就输出位置和时间了,如果不是,那么就在一条边上了

    现在的问题是,怎么样才能确定在这条边上呢?

    好吧,我也不知道,没有想出来,看着书上的做法的,很好啊!

    poj_1135
    #include<cstdio>
    #include<cstring>
    
    const int maxn(555);
    const int inf(100000000);
    
    int n, m;
    int g[maxn][maxn];
    int dist[maxn], vis[maxn];
    void solve(int z){
        memset(vis, 0, sizeof vis);
        for(int i = 1; i <= n; i ++) dist[i] = g[1][i];
        vis[1] = 1;
        dist[1] = 0;
        for(int i = 1; i < n; i ++){
            int min = inf, u;
            for(int j = 1; j <= n; j ++){
                if(!vis[j] && dist[j] < min){
                    min = dist[j];
                    u = j;
                }
            }
            if(min == inf) break;
            vis[u] = 1;
            for(int j = 1; j <= n; j ++){
                if(!vis[j] && g[u][j] < inf && dist[u] + g[u][j] < dist[j])
                  dist[j] = dist[u] + g[u][j];
            }
        }
        int pos, pos1, pos2;
        double time1 = -1, time2 = -1;
        for(int i = 1; i <= n; i ++){
            if(time1 < dist[i] + 0.0){
                time1 = dist[i] + 0.0;
                pos = i;
            }
        }
        for(int j = 1; j <= n; j ++){
            for(int i = 1; i <= n; i ++){
                double t = (dist[i] + dist[j] + g[j][i]) / 2.0;
                if(g[j][i] < inf && time2 < t){
                    time2 = t;
                    pos1 = j;
                    pos2 = i;
                }
            }
        }
        printf("System #%d\n", z);
        if(time2 > time1)
          printf("The last domino falls after %.1f seconds, between key dominoes %d and %d.\n\n", time2, pos1, pos2);
        else
          printf("The last domino falls after %.1f seconds, at key domino %d.\n\n", time1, pos);
    }
    int main(){
        int z = 1;
        while(scanf("%d%d", &n, &m), n||m){
            for(int i = 1; i <= n; i ++)
              for(int j = 1; j <= n; j ++)
                g[i][j] = inf;
            for(int i = 1; i <= m; i ++){
                  int u, v, w;
                  scanf("%d%d%d", &u, &v, &w);
                  g[u][v] = g[v][u] = w;
              }
            solve(z++);
        }
        return 0;
    }

    http://poj.org/problem?id=1149

    好经典的最大流啊,第一次学网络流的时候就是做的这题

    其实这题来学网络流还是挺好的,不过这题的难点是在建图啊。。。。。。。。。。。。。死活也建不出来。

    最大流我只会sap

    poj_1149
    #include<cstdio>
    #include<cstring>
    
    const int inf = 100000000;
    const int maxn = 110;
    int s, t;
    int level[maxn], gap[maxn];
    int cur[maxn], pre[maxn];
    int c[maxn][maxn];
    int m, n;
    
    void input(){
        int last[maxn*10];
        memset(last, 0, sizeof last);
        s = 0, t = n + 1;
        int tmp[maxn * 10];
        memset(c, 0, sizeof c);
        for(int i = 1; i <= m; i ++) scanf("%d", tmp + i);
        for(int i = 1; i <= n; i ++){
            int num;
            scanf("%d", &num);
            while(num --){
                int k;
                scanf("%d", &k);
                if(last[k] == 0)
                  c[s][i] += tmp[k];
                else
                  c[ last[k] ][i] = inf;
                last[k] = i;
            }
            scanf("%d", &num);
            c[i][t] = num;
        }
        n += 2;
    }
    int sap(){
        memset(level, 0, sizeof level);
        memset(gap, 0, sizeof gap);
        memset(cur, 0, sizeof cur);
        int u = pre[s] = s;
        int aug = inf;
        gap[s] = n;
        int v;
        int flow = 0;
        while(level[s] < n){
            for(v = cur[u]; v < n; v ++){
                if(c[u][v] > 0 && level[u] == level[v] + 1){
                    break;
                }
            }
            if(v < n){
                pre[v] = u;
                if(aug > c[u][v]) aug = c[u][v];
                u = cur[u] = v;
                if(u == t){
                    flow += aug;
                    for(v = t; v != s; v = pre[v]){
                        if(c[pre[v]][v] != inf)
                          c[pre[v]][v] -= aug;
                        if(c[v][pre[v]] != inf)
                          c[v][pre[v]] += aug;
                    }
                    aug = inf, u = s;
                }
            }else{
                int min_label = t;
                for(v = 0; v < n; v ++){
                    if(c[u][v] > 0 && min_label > level[v]){
                        cur[u] = v;
                        min_label = level[v];
                    }
                }
                if(--gap[level[u]] == 0) return flow;
                level[u] = min_label + 1;
                gap[level[u]] ++;
                u = pre[u];
            }
        }
        return flow;
    }
    int main(){
        while(~scanf("%d%d", &m, &n)){
            input();
            printf("%d\n", sap());
        }
        return 0;
    }

    http://poj.org/problem?id=1161

    唉。。这题是我见过的最神奇的题了

    主要难点还是解题思路以及建图。。。。。。。。。。Orz太神奇

    以环为点建图!!!

    图构造好了然后就是floyd枚举最小值了

    poj_1161
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int maxn(300);
    const int inf(100000000);
    int n, m;
    struct Person{
        int reg[maxn];
        int num;
        int id;
    }p[maxn];
    int reg[maxn][maxn];
    int g[maxn][maxn];
    int reg_num[maxn];
    int is_ok(int u, int v){
        for(int i = 1; i <= reg_num[u]; i ++){
            for(int j = 1; j <= reg_num[v]; j ++){
                if(reg[u][i] == reg[v][j]){
                    if(reg[u][i-1] == reg[v][j-1]||
                        reg[u][i-1] == reg[v][j+1]||
                        reg[u][i+1] == reg[v][j+1]||
                        reg[u][i+1] == reg[v][j-1])
                      return 1;
                }
            }
        }
        return 0;
    }
    void floyd(){
        for(int k = 1; k <= m; k ++){
            for(int i = 1; i <= m; i ++){
                for(int j = 1; j <= m; j ++){
                    //if(k == i || k == j) continue;
        //            printf("%d ", g[i][j]);
                    g[i][j] = g[j][i] = min(g[i][j], g[i][k] + g[k][j]);
                }
        //        puts("");
            }
        //    puts("\n\n");
        }
        /*
        for(int i = 1; i <= m; i ++){
            for(int j = 1; j < m; j ++)
              printf("%d ", g[i][j]);
            printf("%d\n", g[i][m]);
        }*/
    }
    int num;
    int find(int u){
        int sum = 0;
        for(int i = 0; i < num; i ++){
            int tmp = inf;
            for(int j = 0; j < p[i].num; j ++)
              tmp = min(tmp, g[p[i].reg[j]][u]);
            sum += tmp;
        }
    //    printf("--  %d\n", sum);
        return sum;
    }
    int main(){
        while(~scanf("%d%d", &m, &n)){
            scanf("%d", &num);
            for(int i = 0; i < num; i ++){
                int t;
                scanf("%d", &t);
                p[i].id = t;
                p[i].num = 0;
            }
            for(int i = 1; i <= m; i ++){
                scanf("%d", reg_num + i);
                for(int j = 1; j <= reg_num[i]; j ++){
                    int t;
                    scanf("%d", &t);
                    reg[i][j] = t;
                    for(int k = 0; k < num; k ++)
                      if(t == p[k].id)
                        p[k].reg[p[k].num ++] = i;
                }
                reg[i][0] = reg[i][reg_num[i]];
                reg[i][reg_num[i]+1] = reg[i][1];
            }
            for(int i = 1; i <= m; i ++){
                for(int j = 1; j <= m; j ++){
                    if(i == j){
                        g[i][j] = g[j][i] = 0;
                        continue;
                    }
                    if(is_ok(i, j))
                      g[i][j] = g[j][i] = 1;
                    else 
                      g[i][j] = g[j][i] = inf;
                }
            }
            floyd();
            int ans = inf;
            for(int i = 1; i <= m; i ++){
                int tmp = find(i);
                ans = min(ans, tmp);
            }
            printf("%d\n", ans);
        }
        return 0;
    }

    http://poj.org/problem?id=1201

    差分约束,我已经放弃这一块内容了。。。感觉找公式太难。。

    建图更难

    poj_1201
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int n;
    const int maxn(55555);
    const int inf(100000000);
    struct Edge{
        int v, next, w;
    }e[maxn*10];
    int head[maxn], cnt;
    int l, r;
    void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
        l = inf;
        r = -inf;
    }
    void add_Edge(int u, int v, int w){
        e[cnt].v = v, e[cnt].w = w, e[cnt].next = head[u];
        head[u] = cnt ++;
    }
    int dist[maxn], vis[maxn];
    int q[maxn*10];
    int spfa(){
        for(int i = l; i <= r; i ++) dist[i] = -inf;
        memset(vis, 0, sizeof vis);
        int qs = 0, qe = 0;
        q[qe++] = l;
        vis[l] = 1;
        dist[l] = 0;
        while(qs < qe){
            int u = q[qs++];
            vis[u] = 0;
            for(int i = head[u]; i+1; i = e[i].next){
                int v = e[i].v;
                if(dist[v] < dist[u] + e[i].w){
                    dist[v] = dist[u] + e[i].w;
                    if(!vis[v]){
                        vis[v] = 1;
                        q[qe++] = v;
                    }
                }
            }
        }
        return dist[r] - dist[l];
    }
    int main(){
        while(~scanf("%d", &n)){
            init();
            for(int i = 0; i < n; i ++){
                int a, b, c;
                scanf("%d%d%d", &a, &b, &c);
                l = min(l, a);
                r = max(r, b+1);
                add_Edge(a, b + 1, c);
            }
            for(int i = l; i < r; i ++){
                add_Edge(i, i+1, 0);
                add_Edge(i+1, i, -1);
            }
            printf("%d\n", spfa());
        }
        return 0;
    }

    http://poj.org/problem?id=1236

    这题很好啊。。强连通的题。。

    任务1是求入度为0的点,任务2是求最少加几条边能使这些点变成强连通(我说的点都是指缩点,就是把一个强连通分量看成一个点)

    任务1还好,任务2就麻烦了,看了解题报告之后理解了,就是找入度为0和出度为0的点的个数的最大值了

    可以看下这个。。。http://www.cnblogs.com/louzhang/archive/2012/08/19/2646316.html

    poj_1236
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int maxn(110);
    int belong[maxn], dfn[maxn], low[maxn], vis[maxn];
    struct Edge{
        int v, next;
    }e[maxn*maxn];
    int head[maxn], cnt;
    int in[maxn], out[maxn];
    int n;
    int step, top, color;
    int stack[maxn];
    void init(){
        memset(in, 0, sizeof in);
        memset(out, 0, sizeof out);
        memset(belong, 0, sizeof belong);
        memset(dfn, 0, sizeof dfn);
        memset(low, 0, sizeof low);
        memset(vis, 0, sizeof vis);
        memset(head, -1, sizeof head);
        cnt = 0;
        step = color = top = 0;
    }
    void add_Edge(int u, int v){
        e[cnt].v = v;
        e[cnt].next = head[u];
        head[u] = cnt ++;
    }
    void targan(int u){
        low[u] = dfn[u] = ++ step;
        vis[u] = 1;
        stack[top++] = u;
        for(int i = head[u]; i+1; i = e[i].next){
            int v = e[i].v;
            if(!dfn[v]){
                targan(v);
                if(low[u] > low[v])
                  low[u] = low[v];
            }else
              if(vis[v] && low[u] > dfn[v])
                low[u] = dfn[v];
        }
        ///puts("asdfasdf");
        if(low[u] == dfn[u]){
            color++;
            int s;
            do{
                s = stack[--top];
                vis[s] = 0;
                belong[s] = color;
                //puts("----");
            }while(u != s);
        }
    }
    void solve(){
        for(int i = 1; i <= n; i ++) if(!dfn[i]) targan(i);
        if(color == 1){
            puts("1\n0");
            return;
        }
        //puts("++++");
        int ans1 = 0, ans2 = 0;
        for(int i = 1; i <= n; i ++){
            for(int j = head[i]; j+1; j = e[j].next){
                int v = e[j].v;
                if(belong[i] != belong[v]){
                    in[belong[v]] ++;
                    out[belong[i]] ++;
                }
            }
        }
        //puts("00000");
        for(int i = 1; i <= color; i ++){
            if(in[i] == 0) ans1++;
            if(out[i] == 0) ans2 ++;
        }
        printf("%d\n%d\n", ans1, max(ans1, ans2));
    }
    int main(){
        while(~scanf("%d", &n)){
            int v;
            init();
            for(int i = 1; i <= n; i ++){
                while(scanf("%d", &v), v){
                    add_Edge(i, v);
                }
            }
            solve();
        }
        return 0;
    }

    http://poj.org/problem?id=1251

    MST乱搞即可

    poj_1251
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int maxn(1111);
    const int inf(100000000);
    struct Edge{
        int u, v, next, w;
    }e[maxn];
    int head[maxn], cnt;
    int n;
    int dist[maxn], vis[maxn];
    void init(){
        memset(head, -1, sizeof head);
        cnt = 0;
    }
    void add_Edge(int u, int v, int w){
        e[cnt].u = u, e[cnt].v = v, e[cnt].w = w, e[cnt].next = head[u];
        head[u] = cnt ++;
        e[cnt].u = v, e[cnt].v = u, e[cnt].w = w, e[cnt].next = head[v];
        head[v] = cnt ++;
    }
    void prim(){
        for(int i = 0; i < n; i ++) dist[i] = inf;
        memset(vis, 0, sizeof vis);
        int ans = 0;
        dist[0] = 0;
        for(int i = 0; i < n; i ++){
            int Min = inf, u;
            for(int j = 0; j < n; j ++){
                if(!vis[j] && dist[j] < Min){
                    Min = dist[j];
                    u = j;
                }
            }
            if(Min == inf) break;
            vis[u] = 1;
            ans += Min;
            for(int j = head[u]; j + 1; j = e[j].next){
                int v = e[j].v;
                if(!vis[v] && e[j].w < dist[v])
                  dist[v] = e[j].w;
            }
        }
        printf("%d\n", ans);
    }
    int main(){
        while(scanf("%d", &n), n){
            init();
            for(int i = 1; i < n; i ++){
                char s[3];
                int num;
                scanf("%s%d", s, &num);
                while(num --){
                    char op[3];
                    int w;
                    scanf("%s%d", op, &w);
                    add_Edge(s[0] - 65, op[0] - 65, w);
                }
            }
            prim();
        }
        return 0;
    }

    http://poj.org/problem?id=1273

    最大流

    poj_1273
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int s, t;
    const int inf = 2000000000;
    const int maxn = 300;
    int level[maxn], gap[maxn];
    int c[maxn][maxn], cur[maxn], pre[maxn];
    int n, m;
    int sap(){
        memset(gap, 0, sizeof gap);
        memset(level, 0, sizeof level);
        memset(cur, 0, sizeof cur);
        int    u = pre[s] = s, v;
        gap[s] = n;
        int aug = inf;
        int flow = 0;
        while(level[s] < n){
            for(v = cur[u]; v <= n; v ++){
                if(c[u][v] && level[u] == level[v] + 1) break;
            }
            if(v <= n){
                pre[v] = u;
                aug = min(aug, c[u][v]);
                u = cur[u] = v;
                if(u == t){
                    flow += aug;
                    for(v = t; v != s; v = pre[v]){
                        c[pre[v]][v] -= aug;
                        c[v][pre[v]] += aug;
                    }
                    aug = inf, u = s;
                }
            }else{
                if(--gap[level[u]] == 0) return flow;
                int min_label = n;
                for(v = 1; v <= n; v ++){
                    if(c[u][v] && min_label > level[v]){
                        cur[u] = v;
                        min_label = level[v];
                    }
                }
                level[u] = min_label + 1;
                gap[level[u]]++;
                u = pre[u];
            }
        }
        return flow;
    }
    int main(){
        while(~scanf("%d%d", &m, &n)){
            memset(c, 0, sizeof c);
            while(m --){
                int u, v, w;
                scanf("%d%d%d", &u, &v, &w);
                c[u][v] += w;
            }
            s = 1, t = n;
            printf("%d\n", sap());
        }
        return 0;
    }

    http://poj.org/problem?id=1274

    裸的二分匹配了。。

    poj_1274
    #include<cstdio>
    #include<cstring>
    
    const int maxn = 222;
    int link[maxn], vis[maxn];
    int g[maxn][maxn];
    int n, m;
    int dfs(int u){
        for(int v = 1; v <= m; v ++){
            if(g[u][v] && !vis[v]){
                vis[v] = 1;
                if(link[v] == -1 || dfs(link[v])){
                    link[v] = u;
                    return 1;
                }
            }
        }
        return 0;
    }
    int max_match(){
        memset(link, -1, sizeof link);
        int ans = 0;
        for(int i = 1; i <= n; i ++){
            memset(vis, 0, sizeof vis);
            if(dfs(i)) ans++;
        }
        return ans;
    }
    int main(){
        while(~scanf("%d%d", &n, &m)){
            memset(g, 0, sizeof g);
            for(int i = 1; i <= n; i ++){
                int num;
                scanf("%d", &num);
                while(num --){
                    int t;
                    scanf("%d", &t);
                    g[i][t] = 1;
                }
            }
            printf("%d\n", max_match());
        }
        return 0;
    }

    http://poj.org/problem?id=1325

    二分匹配,就是机器调换来调换去。。。

    poj_1325
    #include<cstdio>
    #include<cstring>
    
    const int maxn(111);
    int link[maxn], vis[maxn], g[maxn][maxn];
    int n, m, k;
    
    int dfs(int u){
        for(int i = 1; i < m; i ++){
            if(g[u][i] && !vis[i]){
                vis[i] = 1;
                if(link[i] == -1 || dfs(link[i])){
                    link[i] = u;
                    return 1;
                }
            }
        }
        return 0;
    }
    int max_match(){
        memset(link, -1, sizeof link);
        int ans = 0;
        for(int i = 1; i < n; i ++){
            memset(vis, 0, sizeof vis);
            ans += dfs(i);
            //if(dfs(i)) ans ++;
        }
        return ans;
    }
    int main(){
        while(scanf("%d", &n), n){
            scanf("%d%d", &m, &k);
            memset(g, 0, sizeof g);
            while(k --){
                int a, u, v;
                scanf("%d%d%d", &a, &u, &v);
                //if(u * v == 0) continue;
                g[u][v] = 1;
            }
            printf("%d\n", max_match());
        }
        return 0;
    }

    http://poj.org/problem?id=1422

    最小路径覆盖 = 点数 - 匹配数

    poj_1422
    #include<cstdio>
    #include<cstring>
    
    const int maxn(1111);
    int link[maxn], vis[maxn], g[maxn][maxn];
    int n, m, k;
    
    int dfs(int u){
        for(int i = 1; i <= n; i ++){
            if(g[u][i] && !vis[i]){
                vis[i] = 1;
                if(link[i] == -1 || dfs(link[i])){
                    link[i] = u;
                    return 1;
                }
            }
        }
        return 0;
    }
    int max_match(){
        memset(link, -1, sizeof link);
        int ans = 0;
        for(int i = 1; i <= n; i ++){
            memset(vis, 0, sizeof vis);
            ans += dfs(i);
            //if(dfs(i)) ans ++;
        }
        return ans;
    }
    int main(){
        int tcase;
        scanf("%d", &tcase);
        while(tcase --){
            memset(g, 0, sizeof g);
            scanf("%d%d", &n, &m);
            while(m --){
                int u, v;
                scanf("%d%d", &u, &v);
                //if(u * v == 0) continue;
                g[u][v] = 1;
            }
            printf("%d\n", n - max_match());
        }
        return 0;
    }

    http://poj.org/problem?id=1459

    唉。。第一个会的最大流

    poj_1459
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int maxn = 111;
    const int inf = 100000000;
    int n, np, nc, m;
    int gap[maxn], level[maxn];
    int cur[maxn], pre[maxn];
    int s, t;
    int c[maxn][maxn];
    
    int sap(){
        memset(gap, 0, sizeof gap);
        memset(cur, 0, sizeof cur);
        memset(level, 0, sizeof level);
        int u = pre[s] = s, v;
        int flow = 0;
        gap[s] = n;
        int aug = inf;
        while(level[s] < n){
            for(v = cur[u]; v < n; v ++){
                if(c[u][v] && level[u] == level[v] + 1) break;
            }
            if(v < n){
                pre[v] = u;
                aug = min(aug, c[u][v]);
                u = cur[u] = v;
                if(u == t){
                    flow += aug;
                    for(v = t; v != s; v = pre[v]){
                        c[pre[v]][v] -= aug;
                        c[v][pre[v]] += aug;
                    }
                    aug = inf, u = s;
                }
            }else{
                if(--gap[level[u]] == 0) return flow;
                int min_label = n;
                for(v = 0; v < n; v ++){
                    if(c[u][v] && min_label > level[v]){
                        min_label = level[v];
                        cur[u] = v;
                    }
                }
                level[u] = min_label + 1;
                gap[level[u]] ++;
                u = pre[u]; 
            }
        }
        return flow;
    }
    int main(){
        while(~scanf("%d%d%d%d", &n, &np, &nc, &m)){
            s = n, t = n + 1, n += 2;
            memset(c, 0, sizeof c);
            while(m--){
                int u, v, w;
                scanf(" (%d,%d)%d", &u, &v, &w);
                c[u][v] += w;
            }
            while(np --){
                int u, w;
                scanf(" (%d)%d", &u, &w);
                c[s][u] += w;
            }
            while(nc --){
                int v, w;
                scanf(" (%d)%d", &v, &w);
                c[v][t] += w;
            }
            printf("%d\n", sap());
        }
        return 0;
    }

    http://poj.org/problem?id=1466

    最大独立集 = 点数 - 匹配数

    不过这题因为双向边,可能匹配两次,所以匹配数得除以2

    poj_1466
    #include<cstdio>
    #include<cstring>
    
    const int maxn(1111);
    int link[maxn], vis[maxn];
    int n;
    int g[maxn][maxn];
    
    int dfs(int u){
        for(int i = 0; i < n; i ++){
            if(g[u][i] && !vis[i]){
                vis[i] = 1;
                if(link[i] == -1 || dfs(link[i])){
                    link[i] = u;
                    return 1;
                }
            }
        }
        return 0;
    }
    int max_match(){
        int ans = 0;
        memset(link, -1, sizeof link);
        for(int i = 0; i < n; i ++){
            memset(vis, 0, sizeof vis);
            ans += dfs(i);
        }
        return ans;
    }
    int main(){
        while(~scanf("%d", &n)){
            memset(g, 0, sizeof g);
            for(int i = 0; i < n; i ++){
                int from, num, to;
                scanf("%d: (%d)", &from, &num);
                while(num--){
                    scanf("%d", &to);
                    g[from][to] = 1;
                }
            }
            printf("%d\n", n - max_match() / 2);
        }
        return 0;
    }

    http://poj.org/problem?id=1469

    二分匹配= =怒了

    poj_1469
    #include<cstdio>
    #include<cstring>
    
    const int maxn(333);
    int link[maxn], vis[maxn];
    int n, p;
    int g[maxn][maxn];
    int dfs(int u){
        for(int i = 1; i <= n; i ++){
            if(g[u][i] && !vis[i]){
                vis[i] = 1;
                if(link[i] == -1 || dfs(link[i])){
                    link[i] = u;
                    return 1;
                }
            }
        }
        return 0;
    }
    int max_match(){
        int ans = 0;
        memset(link, -1, sizeof link);
        for(int i = 1; i <= p; i ++){
            memset(vis, 0, sizeof vis);
            ans += dfs(i);
        }
        return ans;
    }
    int main(){
        int tcase;
        scanf("%d", &tcase);
        while(tcase --){
            scanf("%d%d", &p, &n);
            memset(g, 0, sizeof g);
            for(int i = 1; i <= p; i ++){
                int num;
                scanf("%d", &num);
                while(num --){
                    int t;
                    scanf("%d", &t);
                    g[i][t] = 1;
                }
            }
            if(max_match() == p) puts("YES");
            else
              puts("NO");
        }
        return 0;
    }

    http://poj.org/problem?id=1502

    这题看着解题报告 的啊。。。。题目意思看不明白。。明白了就发现是一图论水题了。。

    poj_1502
    #include<cstdio>
    #include<cstring>
    
    const int maxn(111);
    const int inf(100000000);
    int n;
    int dist[maxn], vis[maxn];
    int g[maxn][maxn];
    
    void dijk(){
        for(int i = 1; i <= n; i ++) dist[i] = inf;
        memset(vis, 0, sizeof vis);
        dist[1] = 0;
        for(int i = 1; i <= n; i ++){
            int min = inf, u;
            for(int j = 1; j <= n; j ++){
                if(!vis[j] && dist[j] < min){
                    min = dist[j];
                    u = j;
                }
            }
            if(min == inf) break;
            vis[u] = 1;
            for(int j = 1; j <= n; j ++){
                if(!vis[j] && g[u][j] < inf && dist[u] + g[u][j] < dist[j])
                  dist[j] = dist[u] + g[u][j];
            }
        }
        int ans = -1;
        for(int i = 1; i <= n; i ++)
          if(ans < dist[i])
            ans = dist[i];
        printf("%d\n", ans);
    }
    int main(){
        while(~scanf("%d", &n)){
            for(int i = 1; i <= n; i ++)
              for(int j = 1; j <= n; j ++)
                if(i == j) g[i][j] = 0;else
                  g[i][j] = inf;
            for(int i = 2; i <= n; i ++){
                for(int j = 1; j < i ; j++){
                    char op[10];
                    scanf("%s", op);
                    if(op[0] == 'x'){
                        g[i][j] = g[j][i] = inf;
                    }else{
                        int t;
                        sscanf(op, "%d", &t);
                        g[i][j] = g[j][i] = t;
                    }
                }
            }
            dijk();
        }
        return 0;
    }

    http://poj.org/problem?id=1511

    最短路,先正向求一次,再反向求一次,加起来即可,这题要用长长整型

    poj_1511
    #include<cstdio>
    #include<cstring>
    
    
    #define ll long long
    const int maxn(1000000+10);
    const ll inf(1ll<<60);
    int n, p;
    struct Edge{
        int v, w, next;
    }e[maxn], ee[maxn];
    int head1[maxn], head2[maxn], cnt1, cnt2;
    void add_Edge(int u, int v, int w){
        e[cnt1].v = v, e[cnt1].w = w, e[cnt1].next = head1[u];
        head1[u] = cnt1 ++;
        ee[cnt2].v = u, ee[cnt2].w = w, ee[cnt2].next = head2[v];
        head2[v] = cnt2 ++;
    }
    void init(){
        memset(head1, -1, sizeof head1);
        memset(head2, -1, sizeof head2);
        cnt1 = cnt2 = 0;
    }
    ll dist1[maxn], dist2[maxn];
    int vis[maxn];
    int q[maxn];
    void spfa1(){
        for(int i = 1; i <= n; i ++) dist1[i] = inf;
        dist1[1] = 0;
        memset(vis, 0, sizeof vis);
        vis[1] = 1;
        int qs = 0, qe = 0;
        q[qe++] = 1;
        while(qs < qe){
            int u = q[qs++];
            vis[u] = 0;
            for(int i = head1[u]; i + 1; i = e[i].next){
                int v = e[i].v;
                if(dist1[v] > dist1[u] + (ll)e[i].w){
                    dist1[v] = dist1[u] + (ll)e[i].w;
                    if(!vis[v]){
                        vis[v] = 1;
                        q[qe++] = v;
                    }
                }
            }
        }
    }
    void spfa2(){
        for(int i = 1; i <= n; i ++) dist2[i] = inf;
        dist2[1] = 0;
        memset(vis, 0, sizeof vis);
        vis[1] = 1;
        int qs = 0, qe = 0;
        q[qe++] = 1;
        while(qs < qe){
            int u = q[qs++];
            vis[u] = 0;
            for(int i = head2[u]; i + 1; i = ee[i].next){
                int v = ee[i].v;
                if(dist2[v] > dist2[u] + (ll)ee[i].w){
                    dist2[v] = dist2[u] + (ll)ee[i].w;
                    if(!vis[v]){
                        vis[v] = 1;
                        q[qe++] = v;
                    }
                }
            }
        }
    }
    void solve(){
        spfa1();
        spfa2();
        ll ans = 0;
        for(int i = 2; i <= n; i ++){
            ll tmp = dist1[i] + dist2[i];
              ans += tmp;
        }
        printf("%lld\n", ans);
    }
    int main(){
        int tcase;
        scanf("%d", &tcase);
        while(tcase --){
            init();
            scanf("%d%d", &n, &p);
            while(p --){
                int u, v, w;
                scanf("%d%d%d", &u, &v, &w);
                add_Edge(u, v, w);
            }
            solve();
        }
        return 0;
    }

    http://poj.org/problem?id=1637

    混合图的欧拉回路问题。。

    可以看下这个 http://www.cnblogs.com/louzhang/archive/2012/08/20/2647784.html

    poj_1637
    #include<cstdio>
    #include<cstring>
    
    const int maxn(222);
    const int inf(100000000);
    int level[maxn], gap[maxn];
    int cur[maxn], pre[maxn];
    struct Edge{
        int v, to, w, next;
    }e[maxn*10];
    int head[maxn], cnt;
    int s, t;
    void add_Edge(int u, int v, int w){
        e[cnt].v = v, e[cnt].w = w, e[cnt].next = head[u];
        head[u] = cnt ++;
        e[cnt].v = u, e[cnt].w = 0, e[cnt].next = head[v];
        head[v] = cnt ++;
    }
    int n, m;
    int in[maxn], out[maxn];
    void init(){
        memset(head, -1, sizeof head);
        cnt = 0;
        memset(in, 0, sizeof in);
        memset(out, 0, sizeof out);
    }
    int f(int a, int b){
        return a > b ? a - b : b - a;
    }
    int sap(){
        memset(gap, 0, sizeof gap);
        memset(level, 0, sizeof level);
        int u = pre[s] = s, v;
        int aug = inf;
        int flow = 0;
        gap[s] = n;
        for(int i = 0; i < n; i ++) cur[i] = head[i];
        while(level[s] < n){
            bool flag = false;
            for(int &i = cur[u]; i + 1; i = e[i].next){
                v = e[i].v;
                if(e[i].w && level[u] == level[v] + 1){
                    flag = true;
                    if(aug > e[i].w) aug = e[i].w;
                    pre[v] = u;
                    u = v;
                    if(u == t){
                        flow += aug;
                        while(u != s){
                            u = pre[u];
                            e[cur[u]].w -= aug;
                            e[cur[u]^1].w += aug;
                        }
                        aug = inf;
                    }
                    break;
                }
            }
            if(flag) continue;
            if(--gap[level[u]] == 0) return flow;
            int min_label = n;
            for(int i = head[u]; i + 1; i = e[i].next){
                v = e[i].v;
                if(level[v] < min_label && e[i].w){
                    cur[u] = i;
                    min_label = level[v];
                }
            }
            level[u] = min_label + 1;
            gap[level[u]] ++;
            u = pre[u];
        }
        return flow;
    }
    int main(){
        int tcase;
        scanf("%d", &tcase);
        while(tcase --){
            init();
            scanf("%d%d", &n, &m);
            int u, v, w;
            while(m --){
                scanf("%d%d%d", &u, &v, &w);
                out[u] ++;
                in[v] ++;
                if(!w)
                  add_Edge(u, v, 1);
            }
            int flag = 0;
            for(int i = 1; i <= n; i ++){
                if(f(in[i], out[i]) & 1){
                    flag = 1;
                    break;
                }
            }
            if(flag){
                puts("impossible");
                continue;
            }
            s = 0, t = n + 1;
            n += 2;
            int sum = 0;
            for(int i = 1; i <= n; i ++){
                int x = out[i] - in[i];
                if(x > 0){
                    sum += x/2;
                    add_Edge(s, i, x/2);
                }else
                  add_Edge(i, t, -x/2);
            }
            //puts("asfs");
            if(sap() == sum)
              puts("possible");
            else
              puts("impossible");
        }
        return 0;
    }

    http://poj.org/problem?id=1716

    跟1201一样的差分约束问题。。

    poj_1716
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int n;
    const int maxn(55555);
    const int inf(100000000);
    struct Edge{
        int v, next, w;
    }e[maxn*10];
    int head[maxn], cnt;
    int l, r;
    void init(){
        cnt = 0;
        memset(head, -1, sizeof head);
        l = inf;
        r = -inf;
    }
    void add_Edge(int u, int v, int w){
        e[cnt].v = v, e[cnt].w = w, e[cnt].next = head[u];
        head[u] = cnt ++;
    }
    int dist[maxn], vis[maxn];
    int q[maxn*10];
    int spfa(){
        for(int i = l; i <= r; i ++) dist[i] = -inf;
        memset(vis, 0, sizeof vis);
        int qs = 0, qe = 0;
        q[qe++] = l;
        vis[l] = 1;
        dist[l] = 0;
        while(qs < qe){
            int u = q[qs++];
            vis[u] = 0;
            for(int i = head[u]; i+1; i = e[i].next){
                int v = e[i].v;
                if(dist[v] < dist[u] + e[i].w){
                    dist[v] = dist[u] + e[i].w;
                    if(!vis[v]){
                        vis[v] = 1;
                        q[qe++] = v;
                    }
                }
            }
        }
        return dist[r] - dist[l];
    }
    int main(){
        while(~scanf("%d", &n)){
            init();
            for(int i = 0; i < n; i ++){
                int a, b, c;
                scanf("%d%d", &a, &b);
                l = min(l, a);
                r = max(r, b+1);
                add_Edge(a, b + 1, 2);
            }
            l = 0;
            for(int i = l; i <= r; i ++){
                add_Edge(i, i+1, 0);
                add_Edge(i+1, i, -1);
            }
            printf("%d\n", spfa());
        }
        return 0;
    }

    http://poj.org/problem?id=1724

    poj_1724
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    
    int k, n, r;
    const int inf(100000000);
    const int maxn(111);
    struct Edge{
        int v, w, c, next;
    }e[maxn*maxn*10];
    int head[maxn], cnt;
    int dist[maxn];
    void add_Edge(int u, int v, int w, int c){
        e[cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].next = head[u];
        head[u] = cnt ++;
    }
    void init(){
        memset(head, -1, sizeof head);
        cnt = 0;
    }
    struct Point{
        int u, dist, c;
        friend bool operator < (const Point &a, const Point &b){
            return a.dist > b.dist;
        }
    };
    int dijk(Point s){
        priority_queue < Point > q;
        q.push(s);
        while(!q.empty()){
            Point tmp = q.top(); 
            q.pop();
            if(tmp.u == n) return tmp.dist;
            for(int i = head[tmp.u]; i + 1; i = e[i].next){
                if(e[i].c + tmp.c <= k){
                    Point now;
                    now.u = e[i].v;
                    now.c = e[i].c + tmp.c;
                    now.dist = e[i].w + tmp.dist;
                    q.push(now);
                }
            }
        }
        return -1;    
    }
    int main(){
        while(~scanf("%d%d%d", &k, &n, &r)){
            init();
            while(r--){
                int u, v, w, c;
                scanf("%d%d%d%d", &u, &v, &w, &c);
                add_Edge(u, v, w, c);
            }
            Point s;
            s.u = 1, s.c = 0, s.dist = 0;
            printf("%d\n", dijk(s));
        }
        return 0;
    }

    有限制的最短路,用dijkstra,在更新的时候,只要cost满足就加入到队列,然后把dist最小的先拿出来,用到了优先队列(堆实现也可以,其实一样)

    poj_1724
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    
    int k, n, r;
    const int inf(100000000);
    const int maxn(111);
    struct Edge{
        int v, w, c, next;
    }e[maxn*maxn*10];
    int head[maxn], cnt;
    int dist[maxn];
    void add_Edge(int u, int v, int w, int c){
        e[cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].next = head[u];
        head[u] = cnt ++;
    }
    void init(){
        memset(head, -1, sizeof head);
        cnt = 0;
    }
    struct Point{
        int u, dist, c;
        friend bool operator < (const Point &a, const Point &b){
            return a.dist > b.dist;
        }
    };
    int dijk(Point s){
        priority_queue < Point > q;
        q.push(s);
        while(!q.empty()){
            Point tmp = q.top(); 
            q.pop();
            if(tmp.u == n) return tmp.dist;
            for(int i = head[tmp.u]; i + 1; i = e[i].next){
                if(e[i].c + tmp.c <= k){
                    Point now;
                    now.u = e[i].v;
                    now.c = e[i].c + tmp.c;
                    now.dist = e[i].w + tmp.dist;
                    q.push(now);
                }
            }
        }
        return -1;    
    }
    int main(){
        while(~scanf("%d%d%d", &k, &n, &r)){
            init();
            while(r--){
                int u, v, w, c;
                scanf("%d%d%d%d", &u, &v, &w, &c);
                add_Edge(u, v, w, c);
            }
            Point s;
            s.u = 1, s.c = 0, s.dist = 0;
            printf("%d\n", dijk(s));
        }
        return 0;
    }

    http://poj.org/problem?id=1780

    欧拉路径问题,书上的。。

    poj_1780
    #include<cstdio>
    #include<cstring>
    const int maxn(100000);
    int list[maxn];
    int stack[maxn*10];
    char ans[maxn*10];
    int s, a;
    void f(int v, int m){
        while(list[v] < 10){
            int w = v * 10 + list[v];
            list[v] ++;
            stack[s++] = w;
            v = w %m;
        }
    }
    int main(){
        int n;
        while(~scanf("%d", &n), n){
            if(n == 1) {
                puts("0123456789");
                continue;
            }
            s = 0, a = 0;
            int v = 0;
            int m = 1;
            for(int i = 1; i < n; i ++) m *= 10;
            memset(list, 0, sizeof list);
            f(v, m);
            while(s){
                v = stack[--s];
                ans[a++] = v % 10 + 48;
                v /= 10;
                f(v, m);
            }
            for(int i = 1; i < n; i ++) printf("0");
            while(a) putchar(ans[--a]);
            puts("");
        }
        return 0;
    }
  • 相关阅读:
    一位资深程序员大牛给予Java初学者的学习路线建议
    Java基础部分全套教程.
    Java进阶面试问题列表
    成为伟大程序员的 10 个要点
    一位资深程序员大牛给予Java初学者的学习路线建议
    2年Java开发工作经验面试总结
    有效处理Java异常三原则
    Java打飞机小游戏(附完整源码)
    原生ajax封装,包含post、method方式
    手机端布局,rem布局动态获取根字体大小
  • 原文地址:https://www.cnblogs.com/louzhang/p/2649143.html
Copyright © 2020-2023  润新知