poj 图算法

   ”一蹦三跳“的总算是把图算法写完了,关于割边和割点的没有看,一些题目死活不过的,也没有继续改,各种模糊,各种纠结呀。(中间加杂着考试,课设,还有放假,总之写的很乱,题意的解释,思路的解释,有的直接没解释了,都很乱,代码也没有解释,有的代码也没有贴)

1. 是差分约束系统,笼统的说就是求解关于一组变量的特殊不等式组的方法。如果你给系统是由n个变量m个约束条件组成,且每个约束条件都形如不等式,那么我们可以从这m个约束条件里发现类似最短路中的三角不等式d[v] <=d[u]+w[u,v],所以差分约束系统就可以转换为单源最短路去求解,主要是看懂题意,建图,然后就是最短路了(注意最短路权值有可能为负)

题目链接 http://poj.org/problem?id=2983

题意:给你一些关系,问你是否叙述合理。把等号转换为不等号,注意负环判断

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <math.h>
 6 #include <queue>
 7 #define N 200010
 8 #define inf 9999999
 9 
10 using namespace std;
11 
12 struct node
13 {
14     int x;
15     int y;
16     int wei;
17 }e[N];
18 int n,cnt;
19 int dis[1010];
20 bool blem()
21 {
22     int i,j;
23     for(i = 1; i <= n; i++)
24     {
25         dis[i] = inf;
26     }
27     dis[1] = 0;
28     for(i = 0; i < n - 1; i++)
29     {
30         int flag = 0;
31         for(j = 0; j < cnt; j++)
32         {
33             if(dis[e[j].y] > dis[e[j].x] + e[j].wei)
34             {
35                 dis[e[j].y] = dis[e[j].x] + e[j].wei;
36                 flag = 1;
37             }
38         }
39         if(!flag) return true;
40     }
41     for(j = 0; j < cnt; j++)
42     {
43         if(dis[e[j].y] > dis[e[j].x] + e[j].wei)
44         {
45             dis[e[j].y] = dis[e[j].x] + e[j].wei;
46             return false;
47         }
48     }
49     return true;
50 }
51 int main()
52 {
53     int i;
54     int a,b,d;
55     int m;
56     char ch;
57     //freopen("data.txt","r",stdin);
58     while(cin>>n>>m)
59     {
60         getchar();
61         cnt = 0;
62         for(i = 0; i < m; i++)
63         {
64             scanf("%c",&ch);
65             if(ch == 'P')
66             {
67                 scanf("%d%d%d",&a,&b,&d);
68                 e[cnt].x = a;
69                 e[cnt].y = b;
70                 e[cnt].wei = -d;
71                 cnt++;
72                 e[cnt].x = b;
73                 e[cnt].y = a;
74                 e[cnt].wei = d;
75                 cnt++;
76             }
77             else
78             {
79                 scanf("%d%d",&a,&b);
80                 e[cnt].x = a;
81                 e[cnt].y = b;
82                 e[cnt].wei = -1;
83                 cnt++;
84             }
85             getchar();
86         }
87         if(blem()) cout<<"Reliable\n";
88         else cout<<"Unreliable\n";
89     }
90     return 0;
91 }

 题目http://poj.org/problem?id=1364

题意:给定长度为N的序列,并给M个关系,要求从第a个序列开始,向后数b个,这些序列之和会<或>某个值,若满足这M个关系,输出"lamentable kingdom",否则输出"successful conspiracy"。

把> < 改为 >=   <=,然后建立不等式关系 x1 - x2 <= n,然后建边dis(x2,x1)=n。然后用最短路求解

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <string>
 5 #include <queue>
 6 #include <algorithm>
 7 #define _clr(a,b) (memset(a,b,sizeof(a)))
 8 #define N 110
 9 
10 using namespace std;
11 
12 struct node
13 {
14     int s,e;
15     int next;
16     int wei;
17 }map[N * 2];
18 int dis[N * 2];
19 int point[N * 2];
20 int v[N * 2];
21 int ans[N * 2];
22 int n,m;
23 int cnt;
24 void init()
25 {
26     _clr(map,0);
27     _clr(point,0xff);
28     cnt = 1;
29 }
30 void add(int s,int e,int d)
31 {
32     map[cnt].s = s;
33     map[cnt].e = e;
34     map[cnt].wei = d;
35     map[cnt].next = point[s];
36     point[s] = cnt++;
37 }
38 int blem()
39 {
40     int i;
41     _clr(dis,0xff);
42     dis[0] = 0;
43     _clr(v,0);
44     _clr(ans,0);
45     queue<int>qu;
46     for(i = 0; i <= n; i++)
47     qu.push(i);
48     //qu.push(0);
49     v[0] = 1;
50     while(!qu.empty())
51     {
52         int temp = qu.front();
53         qu.pop();
54         v[temp] = 0;
55         for(i = point[temp]; i != -1; i = map[i].next)
56         {
57             if(dis[map[i].e] > dis[temp] + map[i].wei)
58             {
59                 dis[map[i].e] = dis[temp] + map[i].wei;
60                 if(!v[map[i].e])
61                 {
62                     v[map[i].e] = 1;
63                     qu.push(map[i].e);
64                     ans[map[i].e] ++;
65                     if(ans[map[i].e] > n) return 0;
66                 }
67             }
68         }
69     }
70     return 1;
71 }
72 int main()
73 {
74     int i;
75     int a,b,d;
76     string ch;
77     //freopen("data.txt","r",stdin);
78     while(cin>>n>>m)
79     {
80         init();
81         for(i = 0; i < m; i++)
82         {
83             cin>>a>>b>>ch>>d;
84             if(ch == "gt")
85             {
86                 add(a + b,a - 1, -d - 1);
87             }
88             else if(ch == "lt")
89             {
90                 add(a - 1,a + b,d - 1);
91             }
92         }
93         if(!blem()) printf("successful conspiracy\n");
94         else printf("lamentable kingdom\n");
95     }
96     return 0;
97 }

题目:http://poj.org/problem?id=3159

题意: n个小朋友分糖,A 同学不能容忍 B 同学的糖比他多k+1(最多能多k) ,要你求n号同学最多能多1号同学多少颗糖。

分析:也就是 ai+k<=aj   =>   aj - ai <=k,差分约束系统 满足条件的a序列转成最短路径dis[j] -dis[i] <=w(i,j)最后求dis[n]-dis[1]即可,这天n 和 m 都挺大,最好用spfa来求解最短路(代码不贴了)

2. 最小费用最大流,http://www.cppblog.com/Icyflame/archive/2009/06/30/88891.html 一个简单的讲解,但是给出了核心代码。

题目:http://poj.org/problem?id=2516

题意:给出N个商店,M个仓库,K种货物,商店的需求,仓库的存货量,以及运输过程中各种货物的运费,求商店的需求能否得到满足,若满足,花费最小的运费是多少。

View Code
  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <iostream>
  4 #include <queue>
  5 #include <algorithm>
  6 #define N 110
  7 #define inf 99999999
  8 #define _clr(a,val) (memset(a,val,sizeof(a)))
  9 
 10 using namespace std;
 11 
 12 int map[N][N], flow[N][N], cost[N][N];
 13 int pre[N], min_flow[N], dis[N];
 14 int spfa(int num,int s,int e)
 15 {
 16     queue<int>qu;
 17     int i;
 18     for(i = 0; i < num; i++)
 19     {
 20         dis[i] = inf;
 21     }
 22     _clr(pre,-1);
 23     qu.push(s);
 24     dis[s] = 0;
 25     min_flow[s] = inf;
 26     while(!qu.empty())
 27     {
 28         int tem = qu.front();
 29         qu.pop();
 30         for(i = 0; i < num; i++)
 31         {
 32             if((map[tem][i] - flow[tem][i] > 0) && (dis[tem] + cost[tem][i] < dis[i]))
 33             {
 34                 dis[i] = dis[tem] + cost[tem][i];
 35                 pre[i] = tem;
 36                 qu.push(i);
 37                 min_flow[i] = min(min_flow[tem],(map[tem][i] - flow[tem][i]));
 38             }
 39         }
 40     }
 41     if(pre[e] != -1) return 1;
 42     return 0;
 43 }
 44 
 45 int mcmf(int num,int s,int e)
 46 {
 47     int t, ans = 0;
 48     _clr(flow,0);
 49     while(spfa(num,s,e))
 50     {
 51         t = e;
 52         while(pre[t] >= 0)
 53         {
 54             flow[pre[t]][t] += min_flow[e];
 55             flow[t][pre[t]] = -flow[pre[t]][t];
 56             t = pre[t];
 57         }
 58         ans += dis[e] * min_flow[e];
 59     }
 60     return ans;
 61 }
 62 
 63 int main()
 64 {
 65     int n,m,kind,ans;
 66     bool no_ans;
 67     int order[N][N],storage[N][N];
 68     int i,j,k;
 69     //freopen("data.txt","r",stdin);
 70     while(scanf("%d%d%d",&n,&m,&kind))
 71     {
 72         if(!n && !m && !kind) break;
 73         no_ans = 0;
 74         ans = 0;
 75         for(i = 0; i < n; i++)
 76         for(j = 0; j < kind; j++)
 77         scanf("%d",&order[i][j]);
 78         for(i = 0; i < m; i++)
 79         for(j = 0; j < kind; j++)
 80         scanf("%d",&storage[i][j]);
 81         for(i = 0; i < kind; i++)
 82         {
 83             int sum1 = 0;
 84             int sum2 = 0;
 85             for(j = 0; j < n; j++)
 86             sum1 += order[j][i];
 87             for(j = 0; j < m; j++)
 88             sum2 += storage[j][i];
 89             if(sum1 > sum2)
 90             {
 91                 no_ans = 1;
 92                 ans = -1;
 93                 break;
 94             }
 95         }
 96         for(i = 0; i < kind; i++)
 97         {
 98             _clr(cost,0);
 99             for(j = 0; j < n; j++)
100             {
101                 for(k = 0; k < m; k++)
102                 {
103                     scanf("%d",&cost[n + k][j]);
104                     cost[j][n + k] = -cost[n + k][j];
105                 }
106             }
107             if(no_ans) continue;
108             else
109             {
110                 _clr(map,0);
111                 for(j = 0; j < n; j++)
112                 map[j][n + m] = order[j][i];
113                 for(j = 0; j < m; j++)
114                 map[n + m + 1][j + n] = storage[j][i];
115                 for(j = n; j < n + m; j++)
116                 {
117                     for(k = 0; k < n; k++)
118                     map[j][k] = 10;
119                 }
120                 ans += mcmf(n + m + 2, n + m + 1, m + n);
121             }
122         }
123         printf("%d\n",ans);
124     }
125     return 0;
126 }

题目:http://poj.org/problem?id=2195

题意:有n个小孩和n个房间,问每个小孩都有一个房间的最小花费

View Code
  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <iostream>
  4 #include <queue>
  5 #include <stdlib.h>
  6 #define N 210
  7 #define inf 1000000001
  8 #define _clr(a,val) (memset(a,val,sizeof(a)))
  9 
 10 using namespace std;
 11 
 12 struct node
 13 {
 14     int x,y;
 15 }man[N],house[N];
 16 char str[N][N];
 17 int map[N][N];
 18 int cost[N][N];
 19 int n,m;
 20 int nman,nhouse;
 21 int ans;
 22 void mcmf(int s,int e,int n)
 23 {
 24     int i;
 25     queue<int>qu;
 26     int d[N],flow[N][N],pre[N];
 27     _clr(flow,0);
 28     int c,f;
 29     f = c = 0;
 30     for(;;)
 31     {
 32         int inq[N];
 33         for(i = 0; i < n; i++)
 34         d[i] = inf;
 35         d[s] = 0;
 36         while(!qu.empty()) qu.pop();
 37         _clr(inq,0);
 38         inq[s] = 1;
 39         qu.push(s);
 40         while(!qu.empty())
 41         {
 42             int u = qu.front();
 43             qu.pop();
 44             inq[u] = 0;
 45             for(i = 0; i < n; i++)
 46             if(map[u][i] > flow[u][i] && d[i] > d[u] + cost[u][i])
 47             {
 48                 d[i] = d[u] + cost[u][i];
 49                 pre[i] = u;
 50                 if(!inq[i])
 51                 {
 52                     inq[i] = 1;qu.push(i);
 53                 }
 54             }
 55         }
 56         if(d[e] == inf) 
 57         {
 58             break;
 59         }
 60         int a = inf;
 61         for(i = e; i != s; i = pre[i])
 62         {
 63             if(a > map[pre[i]][i] - flow[pre[i]][i])
 64             a = map[pre[i]][i] - flow[pre[i]][i];
 65         }
 66         for(i = e; i != s; i = pre[i])
 67         {
 68             flow[pre[i]][i] += a;
 69             flow[i][pre[i]] -= a;
 70         }
 71         ans += d[e] * a;
 72         f += a;
 73     }
 74 }
 75 int main()
 76 {
 77     int i,j;
 78     //freopen("data.txt","r",stdin);
 79     while(scanf("%d%d",&n,&m),m + n)
 80     {
 81         getchar();
 82         nman = nhouse = 0;
 83         for(i = 0; i < n; i++)
 84         {
 85             for(j = 0; j < m; j++)
 86             {
 87                 cin>>str[i][j];
 88                 if(str[i][j] == 'm')
 89                 {
 90                     man[nman].x = i;
 91                     man[nman].y = j;
 92                     nman++;
 93                 }
 94                 else if(str[i][j] == 'H')
 95                 {
 96                     house[nhouse].x = i;
 97                     house[nhouse].y = j;
 98                     nhouse++;
 99                 }
100             }
101         }
102         int num = nman + nhouse;
103         _clr(map,0);
104         for(i = 0; i < num + 2; i++)
105         {
106             for(j = 0; j < num + 2; j++)
107             cost[i][j] = inf;
108         }
109         for(i = 0; i < nman; i++)
110         {
111             for(j = 0; j < nhouse; j++)
112             {
113                 map[i + 1][j + nman + 1] = 1;
114                 cost[i + 1][j + nman + 1] = abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y);
115                 cost[j + nman + 1][i + 1] = -cost[i + 1][j + nman + 1];
116             }
117         }
118         for(i = 1; i <= nman; i++)
119         {
120             map[0][i] = 1;
121             cost[0][i] = 0;
122         }
123         for(i = nman + 1; i <= num; i++)
124         {
125             map[i][num + 1] = 1;
126             cost[i][num + 1] = 0;
127         }
128         ans = 0;
129         mcmf(0,num + 1,num + 2);
130         cout<<ans<<endl;
131     }
132     return 0;
133 }

3. 强连通分量,强连通分量的定义参见维基百科  http://zh.wikipedia.org/wiki/%E5%BC%BA%E8%BF%9E%E9%80%9A%E5%88%86%E9%87%8F 虽然说是有三种方法求解,但看网上的介绍主要是用tarjin算法来写的,感觉这个人写的很详细http://www.byvoid.com/blog/scc-tarjan/对照着他的代码,和画的图,理解算法应该是不难的。

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1269

最裸的模板套用,以前看题还以为是根据dfs搜路径,然后再倒着搜一遍。原来是强连通分量题目,题意就不说了。

判断所给的点是不是在一个强连通分量里,如果是则输出“YES”,否则’NO“

View Code
 1 #include <iostream>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <stack>
 5 #include <queue>
 6 #include <math.h>
 7 #include <stdlib.h>
 8 #include <stdio.h>
 9 #define N 10010
10 #define M 50010
11 #define _clr(a,val) (memset(a,val,sizeof(a)))
12 
13 using namespace std;
14 
15 struct node
16 {
17     int from;
18     int to;
19     int next;
20 }eage[M * 2];
21 stack<int>st;
22 int n,m;
23 int dfn[N],low[N];
24 int v[N],head[N];
25 int bh[N],val[N];
26 int out[N];
27 int num,cou,ind;
28 void add(int f,int t)
29 {
30     eage[num].from = f;
31     eage[num].to = t;
32     eage[num].next = head[f];
33     head[f] = num++;
34 }
35 void tarjin(int u)
36 {
37     int j,t,s;
38     dfn[u] = low[u] = ind++;
39     v[u] = 1;
40     st.push(u);
41     for(j = head[u]; j != -1; j = eage[j].next)
42     {
43         t = eage[j].to;
44         if(!v[t])
45         {
46             tarjin(t);
47             low[u] = min(low[u],low[t]);
48         }
49         else low[u] = min(low[u],dfn[t]);
50     }
51     //cout<<"{";
52     if(dfn[u] == low[u])
53     {
54         cou++;
55         do
56         {
57             s = st.top();
58             st.pop();
59             //cout<<s<<",";
60             bh[s] = cou;
61         }while(s != u);
62         //cout<<"}";
63     }
64 }
65 int main()
66 {
67     int i;
68     int x,y;
69     //freopen("data.txt","r",stdin);
70     while(scanf("%d%d",&n,&m) != EOF)
71     {
72         if(!n && !m) break;
73         _clr(head,-1);
74         _clr(v,0);
75         _clr(dfn,0);
76         _clr(low,0);
77         _clr(bh,0);
78         num = ind = cou = 0;
79         while(m--)
80         {
81             scanf("%d%d",&x,&y);
82             add(x,y);
83         }
84 
85         for(i = 1; i <= n; i++)
86         if(!v[i]) tarjin(i);
87         //cout<<"*****\n";
88         int tem = bh[1];
89         int flag = 0;
90         for(i = 1; i <= n; i++)
91         {
92             if(tem != bh[i]) {flag = 1; break;}
93         }
94         if(!flag) cout<<"Yes\n";
95         else cout<<"No\n";
96     }
97     return 0;
98 }

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3836

简单的题意就是:给出一个连通图,问加几条边可以让这个连通图变为强量同分量 。max(入度为零的个数,出度为零的个数),如果原图是一个强连通的,那么输出0

View Code
 1 #include<iostream>
 2 #include<string.h>
 3 #include<algorithm>
 4 #include<stdio.h>
 5 #include<string>
 6 #define N 20005
 7 #define M 500005
 8 using namespace std;
 9 bool istack[N];
10 int dfn[N],low[N],in[N],out[N],belong[N],stack[N],head[N];
11 typedef struct str
12 {
13     int to;
14     int next;
15 }Node;
16 Node node[M];
17 int res,num,top,ind,n,m;
18 void init()
19 {
20     memset(istack,false,sizeof(istack));
21     memset(head,-1,sizeof(head));
22     memset(dfn,0,sizeof(dfn));
23     memset(low,0,sizeof(low));
24     memset(in,0,sizeof(in));
25     memset(out,0,sizeof(out));
26     memset(stack,0,sizeof(stack));
27     memset(belong,0,sizeof(belong));
28     res=num=top=0;
29     ind=1;
30 }
31 void dfs(int i)
32 {
33     dfn[i]=low[i]=ind++;
34     istack[i]=true;
35     stack[top++]=i;
36     for(int j=head[i];j!=-1;j=node[j].next)
37     {
38         int v=node[j].to;
39         if(!dfn[v])
40         {
41             dfs(v);
42             low[i]=min(low[i],low[v]);
43         }
44         else if(istack[v])
45             low[i]=min(low[i],dfn[v]);
46     }
47     int u;
48     if(dfn[i]==low[i])
49     {
50         res++;
51         do
52         {
53              u=stack[--top];
54              istack[u]=false;
55              belong[u]=res;
56         }while(u!=i);
57      }
58 }
59 void tarjan()
60 {
61     for(int i=1;i<=n;++i)
62         if(!dfn[i]) dfs(i);
63 }
64 void solve()
65 {   if(res==1) {cout<<"0"<<endl;return;}
66     for(int i=1;i<=n;++i)
67         for(int j=head[i];j!=-1;j=node[j].next)
68            if(belong[i]!=belong[node[j].to])
69            {
70                out[belong[i]]++;
71                in[belong[node[j].to]]++;
72            }
73            int p=0,q=0;
74            for(int i=1;i<=res;++i)
75            {
76                if(!out[i]) p++;
77                if(!in[i]) q++;
78            }
79            cout<<max(p,q)<<endl;
80 }
81 int main()
82 {
83     //freopen("data.txt","r",stdin);
84     while(cin>>n>>m)
85     {
86       init();
87       for(int i=0;i!=m;++i)
88       {
89           int a,b;
90            cin>>a>>b;
91            node[num].to = b;
92            node[num].next = head[a];
93            head[a] = num++;
94       }
95       tarjan();
96       solve();
97     }return 0;
98 }

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

题意:N个高校之间有一些单向的网络链接(N<100),当发布一个软件时,学校i收到软件时,它可以将软件发送给所有它链接到的学校。现在要求发布一款软件,最少需要发给多少个学校,使得所有学校都可以收到软件(问题A)。最少需要添加多少条单向网络链接,可以使得将软件任意发给一个学校,使得所有学校都可以收到(问题B)。

问题A被称为求最小基点问题,首先,求出有向图的极大强连通分量,在同一个强连通分量里的学校任意一个收到软件,整个强连通分量里的学校都可以收到。将每个强连通分量缩成一个点,构成一个新的有向无环图。当强连通分量i收到软件,那么i可达的强连通分量都可以收到软件。

我们称入度为0的强连通分量为最高强连同分量。显然,每个最高强连通分量都必须单独发送一次软件,而其他强连通分量都可以通过最高强连通分量到达。所以,最高强连通分量的个数也就是问题A的答案

问题B,是max(入度为零的个数,出度为零的个数)注意的是,当原图只有一个强连通分量是,问题B的答案是0。

View Code
  1 #include <iostream>
  2 #include <string.h>
  3 #include <algorithm>
  4 #include <stack>
  5 #include <queue>
  6 #include <math.h>
  7 #include <stdlib.h>
  8 #include <stdio.h>
  9 #define N 101
 10 #define M 10010
 11 #define inf 100000000
 12 #define _clr(a,val) (memset(a,val,sizeof(a)))
 13 
 14 using namespace std;
 15 
 16 struct node
 17 {
 18     int from;
 19     int to;
 20     int next;
 21 }eage[M * 2];
 22 int dfn[N],low[N];
 23 int head[N],v[N];
 24 int in[N],out[N];
 25 int map[N][N];
 26 int bh[N];
 27 int ind,num,cou;
 28 stack<int>st;
 29 int n,m;
 30 void add(int f,int t)
 31 {
 32     eage[num].from = f;
 33     eage[num].to = t;
 34     eage[num].next = head[f];
 35     head[f] = num++;
 36 }
 37 void tarjin(int i)
 38 {
 39     int j,s,t;
 40     dfn[i] = low[i] = ++ind;
 41     v[i] = 1;
 42     st.push(i);
 43     for(j = head[i]; j != -1; j = eage[j].next)
 44     {
 45         t = eage[j].to;
 46         if(!dfn[t])
 47         {
 48             tarjin(t);
 49             low[i] = min(low[i],low[t]);
 50         }
 51         else if(v[t]) low[i] = min(dfn[t],low[i]);
 52     }
 53     if(dfn[i] == low[i])
 54     {
 55         cou++;
 56         do
 57         {
 58             s = st.top();
 59             st.pop();
 60             bh[s] = cou;
 61             v[s] = 0;
 62         }while(i != s);
 63     }
 64 }
 65 void ca()
 66 {
 67     int i,j;
 68     for(i = 1; i <= n; i++)
 69     if(!dfn[i]) tarjin(i);
 70     _clr(out,0);
 71     _clr(in,0);
 72     for(i = 1; i <= n; i++)
 73     {
 74         for(j = head[i]; j != -1; j = eage[j].next)
 75         {
 76             int x = bh[i];
 77             int y = bh[eage[j].to];
 78             if(x != y)
 79             {
 80                 out[x]++;
 81                 in[y]++;
 82             }
 83         }
 84     }
 85     int sum = 0;
 86     int ttsum = 0;
 87     for(i = 1;i <= cou; i++)
 88     {
 89         if(!in[i]) sum++;
 90     }
 91     if(cou == 1)
 92     {
 93         cout<<sum<<"\n0\n";
 94         return ;
 95     }
 96     else
 97     for(i = 1;i <= cou; i++)
 98     {
 99         if(!out[i]) ttsum++;
100     }
101     cout<<sum<<"\n"<<max(sum,ttsum)<<endl;
102 }
103 int main()
104 {
105     int i;
106     int x;
107     //freopen("data.txt","r",stdin);
108     while(cin>>n)
109     {
110         _clr(head,-1);
111         _clr(dfn,0);
112         _clr(v,0);
113         _clr(low,0);
114         _clr(bh,0);
115         ind = 0;
116         cou = num = 0;
117         for(i = 1; i <= n; i++)
118         {
119             while(cin>>x,x)
120             {
121                 add(i,x);
122             }
123         }
124         ca();
125     }
126     return 0;
127 }

题目:http://poj.org/problem?id=2942

题目大意:骑士在圆桌上开会人数是奇数(大于1) 互相憎恨的骑士不能做在一起,问有多少个骑士永远不能坐在圆桌上,注意可以不同时坐在一起 可以分批

首先是求出图中含有的块,然后找奇圈,一个连通分量里面只要有奇圈,那么这个分量里面的所有的点都可以在某个奇圈里面,判断是否为奇圈的方法是看这个图是否为二分图,如果是二分图,则一定没有奇圈,判断二分图的方法是用染色法,dfs黑白染色,将一顶点a染成黑色,和a相邻的点染成白色。这样如果一条边上的两个点的颜色相同,说明该图不是二分图。

View Code
  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <iostream>
  4 #include <stack>
  5 #define N 1010
  6 #define M 1000010
  7 #define _clr(a,val) (memset(a,val,sizeof(a)))
  8 
  9 using namespace std;
 10 
 11 struct node
 12 {
 13     int from;
 14     int to;
 15     int next;
 16 }eage[M * 2];
 17 stack<int>st;
 18 int n,m;
 19 int num,cnt;
 20 int flag,cou;
 21 int color[N],bh[N];
 22 int v[N],vis[N];
 23 int map[N][N];
 24 int head[N];
 25 int dfn[N],low[N];
 26 int val[N];
 27 void add(int f,int t)
 28 {
 29     eage[num].from = f, eage[num].to = t;
 30     eage[num].next = head[f], head[f] = num++;
 31     eage[num].from = t, eage[num].to = f;
 32     eage[num].next = head[t], head[t] = num++;
 33 }
 34 void dfs(int ind,int col)
 35 {
 36     int i,t;
 37     color[ind] = col;
 38     for(i = head[ind]; i != -1; i = eage[i].next)
 39     {
 40         t = eage[i].to;
 41         if(bh[t] != cou) continue;
 42         if(color[t] == 1 - col) continue;
 43         if(color[t] == -1) dfs(t,1 - col);
 44         else if(color[t] == col) flag = 1;
 45         if(flag) return ;
 46     }
 47 }
 48 void tarjin(int u,int f)
 49 {
 50     int i,t,s,j,ans;
 51     dfn[u] = low[u] = cnt++;
 52     vis[u] = 1;
 53     st.push(u);
 54     for(i = head[u]; i != -1; i = eage[i].next)
 55     {
 56         t = eage[i].to;
 57         if(t == f) continue;
 58         if(!vis[t])
 59         {
 60             tarjin(t,u);
 61             low[u] = min(low[u],low[t]);
 62             if(low[t] >= dfn[u])
 63             {
 64                 cou++;
 65                 ans = 0;
 66                 do
 67                 {
 68                     s = st.top();
 69                     st.pop();
 70                     val[++ans] = s;
 71                     bh[s] = cou;
 72                 }while(s != t);
 73             bh[u] = cou;
 74             val[++ans] = u;
 75             flag = 0;
 76             _clr(color,-1);
 77             dfs(u,0);
 78             if(flag)
 79             {
 80                 for(j = 1; j <= ans; j++)
 81                 v[val[j]] = 1;
 82             }
 83             }
 84         }
 85         else low[u] = min(low[u],dfn[t]);
 86     }
 87 }
 88 int main()
 89 {
 90     int i,j;
 91     int x,y;
 92     //freopen("data.txt","r",stdin);
 93     while(scanf("%d%d",&n,&m), n + m)
 94     {
 95         _clr(map,0);
 96         while(m--)
 97         {
 98             scanf("%d%d",&x,&y);
 99             map[x][y] = map[y][x] = 1;
100         }
101         num = cnt = cou = 0;
102         _clr(head,-1);
103         for(i = 1; i <= n; i++)
104         {
105             for(j = i + 1; j <= n; j++)
106             if(map[i][j] == 0)
107             {
108                 add(i,j);
109             }
110         }
111         int sum = 0;
112         _clr(bh,-1);
113         _clr(v,0);
114         _clr(vis,0);
115         _clr(dfn,0);
116         _clr(low,0);
117         for(i = 1; i <= n; i++)
118         if(!vis[i]) tarjin(i,-1);
119         for(i = 1; i <= n; i++)
120         if(v[i]) sum++;
121         printf("%d\n",n - sum);
122     }
123     return 0;
124 }

4. KM算法   如果还没有看匈牙利二分匹配的,最好先去看一小那个,km是建立在二分匹配的基础上做的,一个讲解链接 http://www.cppblog.com/MatoNo1/archive/2011/07/23/151724.aspx 

题目:http://poj.org/problem?id=2400

题意: n个雇主n个员工, 每个雇主对每个员工有不同的喜好值0~n-1, 0表示最喜欢, 每个员工对每个雇主也有喜好值, 定义同前, 问怎样分配使得总喜好值对2n个人取平均的值最小, 按字典序输出所有方案. 

把雇主对员工的喜爱值和员工对雇主的喜爱值建立矩阵,然后用km算法模板,km一次,再用dfs搜索路径

View Code
  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <iostream>
  4 #include <algorithm>
  5 #define N 20
  6 #define inf 10000000
  7 #define _clr(a,val) (memset(a,val,sizeof(a)))
  8 
  9 using namespace std;
 10 
 11 int map[N][N],v[N];
 12 int lx[N],ly[N];
 13 int vx[N],vy[N];
 14 int match[N],path[N];
 15 int n,cnt;
 16 int dfs(int x)
 17 {
 18     int i;
 19     vx[x] = 1;
 20     for(i = 1; i <= n; i++)
 21     {
 22         if(!vy[i] && lx[x] + ly[i] == map[x][i])
 23         {
 24             vy[i] = 1;
 25             if(match[i] == -1 || dfs(match[i]))
 26             {
 27                 match[i] = x;
 28                 return 1;
 29             }
 30         }
 31     }
 32     return 0;
 33 }
 34 int km()
 35 {
 36     int i,j,k;
 37     _clr(match,-1);
 38     for(i = 1; i <= n; i++)
 39     {
 40         lx[i] = inf;
 41         for(j = 1; j <= n; j++)
 42         if(lx[i] < map[i][j]) lx[i] = map[i][j];
 43     }
 44     _clr(ly,0);
 45     for(i = 1; i <= n; i++)
 46     {
 47         while(1)
 48         {
 49             _clr(vx,0);
 50             _clr(vy,0);
 51             if(dfs(i)) break;
 52             int minn = inf;
 53             for(j = 1; j <= n; j++)
 54             {
 55                 if(vx[j])
 56                 {
 57                     for(k = 1; k <= n; k++)
 58                     if(!vy[k] && lx[j] + ly[k] - map[j][k] < minn)
 59                     {
 60                         minn = lx[j] + ly[k] - map[j][k];
 61                     }
 62                 }
 63             }
 64             for(j = 1; j <= n; j++)
 65             {
 66                 if(vx[j]) lx[j] -= minn;
 67                 if(vy[j]) ly[j] += minn;
 68             }
 69         }
 70     }
 71     int sum = 0;
 72     for(i = 1; i <= n; i++)
 73     sum -= map[match[i]][i];
 74     return sum;
 75 }
 76 void out(int sum)
 77 {
 78     int i;
 79     if(sum  > n)
 80     {
 81         printf("Best Pairing %d\n",++cnt);
 82         for(i = 1; i <= n; i++)
 83         {
 84             //if(i == n) printf("Supervisor %d with Employee %d\n",i,path[0]);
 85             //else printf("Supervisor %d with Employee %d\n",i,path[i]);
 86             printf("Supervisor %d with Employee %d\n",i,path[i]);
 87         }
 88     }
 89     else
 90     {
 91         for(i = 1; i <= n; i++)
 92         if(lx[sum] + ly[i] == map[sum][i] && !v[i])
 93         {
 94             v[i] = 1;
 95             path[sum] = i;
 96             out(sum + 1);
 97             v[i] = 0;
 98         }
 99     }
100 }
101 int main()
102 {
103     int t,cs = 0;
104     int i,j;
105     int temp;
106     //freopen("data.txt","r",stdin);
107     scanf("%d",&t);
108     while(t--)
109     {
110         _clr(map,0);
111         scanf("%d",&n);
112         for(i = 1; i <= n; i++)
113         {
114             for(j = 0; j < n; j++)
115             {
116                 scanf("%d",&temp);
117                 map[temp][i] -= j;
118             }
119         }
120         for(i = 1; i <= n; i++)
121         {
122             for(j = 0; j < n; j++)
123             {
124                 scanf("%d",&temp);
125                 map[i][temp] -= j;
126             }
127         }
128         int ans = km();
129         printf("Data Set %d, Best average difference: %.6lf\n",++cs,(ans * 1.0) / (2 * n));
130         cnt = 0;
131         _clr(path,0);
132         _clr(v,0);
133         out(1);
134         printf("\n");
135     }
136     return 0;
137 }

题目:

题意: 有N个工件要在M个机器上加工,有一个N*M的矩阵描述其加工时间。 同一时间内每个机器只能加工一个工件,问加工完所有工件后,使得平均加工时间最小。注意工件是有等待时间的,当一个机器在加工一个工件时,其他的都在等待即   若某台机器按顺序执行k个任务,且k个任务的执行时间分别为t1,t2…tk,则k个任务的总的执行时间是
t1*k+t2*(k-1)+t3*(k-2)+…+tk-1*2+tk

建图时   分两个集合  X集有N个点(N个工件),Y集是由拆分成的 N*M个点 组成。即每一个工件I都可能机器J的倒数第K1~N)个顺序完成,则这样建图:w[i][j-1*N+k]  =   -k*tmp[i][j]。然后用KM求最大权

原文地址:https://www.cnblogs.com/fxh19911107/p/2605861.html