poj 1149 PIGS
题意:给你m个猪圈以及每个猪圈里原来有多少头猪,先后给你n个人,每个人能打开一些猪圈并且他们最多想买Ki头猪,在每一个人买完后能将打开的猪圈中的猪顺意分配在这次打开猪圈里,在下一个人来之前 已打开的猪圈被锁上。
思路:这是第一道构图题,所以借鉴了大牛的思想<http://wenku.baidu.com/view/0ad00abec77da26925c5b01c.html>,按照朴素的思路先得到一个图
然后根据下面三个规律:
得到最终的图:
最终可以归纳出本题的构图规则:
然后就是裸的最大流模板了
View Code
1 #include <stdio.h>
2 #include <string.h>
3 #define INF 2100000000
4 #define MAXN 103
5 int map[MAXN][MAXN],vis[1010],v[1010];
6 int SAP(int map[][MAXN],int v_count,int s,int t) //邻接矩阵,节点总数,始点,汇点
7 {
8 int i;
9 int cur_flow,max_flow,cur,min_label,temp; //当前流,最大流,当前节点,最小标号,临时变量
10 char flag; //标志当前是否有可行流
11 int cur_arc[MAXN],label[MAXN],neck[MAXN]; //当前弧,标号,瓶颈边的入点(姑且这么叫吧)
12 int label_count[MAXN],back_up[MAXN],pre[MAXN]; //标号为i节点的数量,cur_flow的纪录,当前流路径中前驱
13
14 //初始化
15 memset(label,0,MAXN*sizeof(int));
16 memset(label_count,0,MAXN*sizeof(int));
17
18 memset(cur_arc,0,MAXN*sizeof(int));
19 label_count[0]=v_count; //全部初始化为距离为0
20
21 neck[s]=s;
22 max_flow=0;
23 cur=s;
24 cur_flow=INF;
25
26 //循环代替递归
27 while(label[s]<v_count)
28 {
29 back_up[cur]=cur_flow;
30 flag=0;
31
32 //选择允许路径(此处还可用邻接表优化)
33 for(i=cur_arc[cur];i<v_count;i++) //当前弧优化
34 {
35 if(map[cur][i]!=0&&label[cur]==label[i]+1) //找到允许路径
36 {
37 flag=1;
38 cur_arc[cur]=i; //更新当前弧
39 if(map[cur][i]<cur_flow) //更新当前流
40 {
41 cur_flow=map[cur][i];
42 neck[i]=cur; //瓶颈为当前节点
43 }
44 else
45 {
46 neck[i]=neck[cur]; //瓶颈相对前驱节点不变
47 }
48 pre[i]=cur; //记录前驱
49 cur=i;
50 if(i==t) //找到可行流
51 {
52 max_flow+=cur_flow; //更新最大流
53
54 //修改残量网络
55 while(cur!=s)
56 {
57 if(map[pre[cur]][cur]!=INF)map[pre[cur]][cur]-=cur_flow;
58 back_up[cur] -= cur_flow;
59 if(map[cur][pre[cur]]!=INF)map[cur][pre[cur]]+=cur_flow;
60 cur=pre[cur];
61 }
62
63 //优化,瓶颈之后的节点出栈
64 cur=neck[t];
65 cur_flow=back_up[cur];
66 }
67 break;
68 }
69 }
70 if(flag)continue;
71
72 min_label=v_count-1; //初始化min_label为节点总数-1
73
74 //找到相邻的标号最小的节点
75 for(i=0;i<v_count;i++)
76 {
77 if(map[cur][i]!=0&&label[i]<min_label)
78 {
79 min_label=label[i];
80 temp=i;
81 }
82 }
83 cur_arc[cur]=temp; //记录当前弧,下次从提供最小标号的节点开始搜索
84 label_count[label[cur]]--; //修改标号纪录
85 if(label_count[label[cur]]==0)break; //GAP优化
86 label[cur]=min_label+1; //修改当前节点标号
87 label_count[label[cur]]++; //修改标号记录
88 if(cur!=s)
89 {
90 //从栈中弹出一个节点
91 cur=pre[cur];
92 cur_flow=back_up[cur];
93 }
94 }
95 return(max_flow);
96 }
97 int main()
98 {
99 int n,m,i,j,num,temp;
100
101 while(scanf("%d%d",&m,&n)!=EOF)
102 {
103 for(i=1;i<=m;i++)
104 scanf("%d",v+i);
105 memset(vis,0,sizeof(vis));
106 memset(map,0,sizeof(map));
107
108 for(j=1;j<=n;j++)
109 {
110 scanf("%d",&num);
111 while(num--)
112 {
113 scanf("%d",&temp);
114 if(vis[temp]==0)
115 map[0][j]+=v[temp],vis[temp]=j;
116 else
117 map[vis[temp]][j]=INF;
118 //puts("!");
119 }
120 scanf("%d",&temp);
121 map[j][n+1]=temp;
122 }
123 printf("%d\n",SAP(map,n+2,0,n+1));
124 }
125 return 0;
126 }
2 #include <string.h>
3 #define INF 2100000000
4 #define MAXN 103
5 int map[MAXN][MAXN],vis[1010],v[1010];
6 int SAP(int map[][MAXN],int v_count,int s,int t) //邻接矩阵,节点总数,始点,汇点
7 {
8 int i;
9 int cur_flow,max_flow,cur,min_label,temp; //当前流,最大流,当前节点,最小标号,临时变量
10 char flag; //标志当前是否有可行流
11 int cur_arc[MAXN],label[MAXN],neck[MAXN]; //当前弧,标号,瓶颈边的入点(姑且这么叫吧)
12 int label_count[MAXN],back_up[MAXN],pre[MAXN]; //标号为i节点的数量,cur_flow的纪录,当前流路径中前驱
13
14 //初始化
15 memset(label,0,MAXN*sizeof(int));
16 memset(label_count,0,MAXN*sizeof(int));
17
18 memset(cur_arc,0,MAXN*sizeof(int));
19 label_count[0]=v_count; //全部初始化为距离为0
20
21 neck[s]=s;
22 max_flow=0;
23 cur=s;
24 cur_flow=INF;
25
26 //循环代替递归
27 while(label[s]<v_count)
28 {
29 back_up[cur]=cur_flow;
30 flag=0;
31
32 //选择允许路径(此处还可用邻接表优化)
33 for(i=cur_arc[cur];i<v_count;i++) //当前弧优化
34 {
35 if(map[cur][i]!=0&&label[cur]==label[i]+1) //找到允许路径
36 {
37 flag=1;
38 cur_arc[cur]=i; //更新当前弧
39 if(map[cur][i]<cur_flow) //更新当前流
40 {
41 cur_flow=map[cur][i];
42 neck[i]=cur; //瓶颈为当前节点
43 }
44 else
45 {
46 neck[i]=neck[cur]; //瓶颈相对前驱节点不变
47 }
48 pre[i]=cur; //记录前驱
49 cur=i;
50 if(i==t) //找到可行流
51 {
52 max_flow+=cur_flow; //更新最大流
53
54 //修改残量网络
55 while(cur!=s)
56 {
57 if(map[pre[cur]][cur]!=INF)map[pre[cur]][cur]-=cur_flow;
58 back_up[cur] -= cur_flow;
59 if(map[cur][pre[cur]]!=INF)map[cur][pre[cur]]+=cur_flow;
60 cur=pre[cur];
61 }
62
63 //优化,瓶颈之后的节点出栈
64 cur=neck[t];
65 cur_flow=back_up[cur];
66 }
67 break;
68 }
69 }
70 if(flag)continue;
71
72 min_label=v_count-1; //初始化min_label为节点总数-1
73
74 //找到相邻的标号最小的节点
75 for(i=0;i<v_count;i++)
76 {
77 if(map[cur][i]!=0&&label[i]<min_label)
78 {
79 min_label=label[i];
80 temp=i;
81 }
82 }
83 cur_arc[cur]=temp; //记录当前弧,下次从提供最小标号的节点开始搜索
84 label_count[label[cur]]--; //修改标号纪录
85 if(label_count[label[cur]]==0)break; //GAP优化
86 label[cur]=min_label+1; //修改当前节点标号
87 label_count[label[cur]]++; //修改标号记录
88 if(cur!=s)
89 {
90 //从栈中弹出一个节点
91 cur=pre[cur];
92 cur_flow=back_up[cur];
93 }
94 }
95 return(max_flow);
96 }
97 int main()
98 {
99 int n,m,i,j,num,temp;
100
101 while(scanf("%d%d",&m,&n)!=EOF)
102 {
103 for(i=1;i<=m;i++)
104 scanf("%d",v+i);
105 memset(vis,0,sizeof(vis));
106 memset(map,0,sizeof(map));
107
108 for(j=1;j<=n;j++)
109 {
110 scanf("%d",&num);
111 while(num--)
112 {
113 scanf("%d",&temp);
114 if(vis[temp]==0)
115 map[0][j]+=v[temp],vis[temp]=j;
116 else
117 map[vis[temp]][j]=INF;
118 //puts("!");
119 }
120 scanf("%d",&temp);
121 map[j][n+1]=temp;
122 }
123 printf("%d\n",SAP(map,n+2,0,n+1));
124 }
125 return 0;
126 }
posted on 2012-07-23 17:07 sleeper_qp 阅读(1649) 评论(0) 编辑 收藏 举报