标签:
从现在开始把每一个我觉得对我来说有新意的图论题目汇集下来
由于目前基本只会网络流,就先来网络流的吧:
1.hdu2883
题意: 有一个烧烤机,每次最多能烤 m 块肉,现在有 n 个人来买烤肉,每个人到达时间为 si,离开时间为 ei,点的烤肉数量为 ci,点的烤肉所需烘烤时间为 di,
每个人要烤的肉可以分成若干份在同时烤,问是否存在一种方案可以满足所有顾客的需求。
分析: 将所有的到达时间和结束时间按升序排序,得到 x <= 2n-1 个时间区间。
建图:
s为源,t为汇,
每个顾客i作为一个结点并连边(s, i, ni*ti)
每个区间j作为一个结点并连边(j, t, (ej-sj)*M),其中sj, ej分别表示区间j的起始时间和终止时间
对任意顾客i和区间j,若 [sj, ej] 完全包含在 [si, ei] 之中,则连边(i, j, INF)
若最大流等于 ∑ni*ti 则是 Yes,否则是 No。
这题我是觉得不科学的,比如一组数据:
1 10
1 2 3 5
顾客要的东西要五分钟烤完,然后你特么的让人家等了2分钟就好了,你是怎么做到的呀O__O "…
当然,如果真的要较真的话这题我就不会做了(捂脸)
代码:
1 #include<iostream> 2 #include<algorithm> 3 #include<queue> 4 #include<cstring> 5 #include<cstdio> 6 #include<climits> 7 #define MAXE 370000 8 #define MAXP 606 9 #define Max(a,b) a>b?a:b 10 #define Min(a,b) a<b?a:b 11 using namespace std; 12 struct Edge 13 { 14 int s,t,f,next; 15 } edge[MAXE]; 16 struct Cust 17 { 18 int start,last,stay; 19 }cust[MAXP]; 20 int head[MAXP]; 21 int time[MAXP*2]; 22 int stay[MAXP]; 23 int cur[MAXP]; 24 int pre[MAXP]; 25 int stack[MAXE]; 26 int used[MAXP]; 27 int ent; 28 int n,m,s,t; 29 int num; 30 void add(int start,int last,int f) 31 { 32 edge[ent].s=start; 33 edge[ent].t=last; 34 edge[ent].f=f; 35 edge[ent].next=head[start]; 36 head[start]=ent++; 37 edge[ent].s=last; 38 edge[ent].t=start; 39 edge[ent].f=0; 40 edge[ent].next=head[last]; 41 head[last]=ent++; 42 } 43 bool bfs(int S,int T) 44 { 45 memset(pre,-1,sizeof(pre)); 46 pre[S]=0; 47 queue<int>q; 48 q.push(S); 49 while(!q.empty()) 50 { 51 int temp=q.front(); 52 q.pop(); 53 for(int i=head[temp]; i!=-1; i=edge[i].next) 54 { 55 int temp2=edge[i].t; 56 if(pre[temp2]==-1&&edge[i].f) 57 { 58 pre[temp2]=pre[temp]+1; 59 q.push(temp2); 60 } 61 } 62 } 63 return pre[T]!=-1; 64 } 65 int dinic(int start,int last) 66 { 67 int flow=0,now; 68 while(bfs(start,last)) 69 { 70 int top=0; 71 memcpy(cur,head,sizeof(head)); 72 int u=start; 73 while(1) 74 { 75 if(u==last)//如果找到终点结束对中间路径进行处理并计算出该流 76 { 77 int minn=INT_MAX; 78 for(int i=0; i<top; i++) 79 { 80 if(minn>edge[stack[i]].f) 81 { 82 minn=edge[stack[i]].f; 83 now=i; 84 } 85 } 86 for(int i=0;i<top;i++) 87 { 88 edge[stack[i]].f-=minn; 89 edge[stack[i]^1].f+=minn; 90 } 91 flow+=minn; 92 top=now; 93 u=edge[stack[top]].s; 94 } 95 for(int i=cur[u]; i!=-1; cur[u]=i=edge[i].next) //找出从u点出发能到的边 96 if(edge[i].f&&pre[edge[i].t]==pre[u]+1) 97 break; 98 if(cur[u]==-1)//如果从该点未找到可行边,将该点标记并回溯 99 { 100 if(top==0)break; 101 pre[u]=-1; 102 u=edge[stack[--top]].s; 103 } 104 else//如果找到了继续运行 105 { 106 stack[top++]=cur[u]; 107 u=edge[cur[u]].t; 108 } 109 } 110 } 111 return flow; 112 } 113 int main() 114 { 115 while(~scanf("%d%d",&n,&m)) 116 { 117 int si,ni,ti; 118 int sum=0; 119 memset(head,-1,sizeof(head)); 120 ent=0; 121 s=0;t=3*n+1; 122 int tot=0; 123 for(int i=1;i<=n;i++) 124 { 125 scanf("%d%d%d%d",&cust[i].start,&ni,&cust[i].last,&ti); 126 cust[i].stay=ni*ti; 127 sum+=cust[i].stay; 128 time[tot++]=cust[i].start; 129 time[tot++]=cust[i].last; 130 } 131 sort(time,time+2*n); 132 for(int i=1;i<=n;i++) 133 add(s,i,cust[i].stay);//cout<<"road:"<<i<<" start:"<<cust[i].start<<" last:"<<cust[i].last<<endl;} 134 //cout<<"time[0]:"<<time[0]<<endl; 135 for(int i=1;i<2*n;i++) 136 { 137 //cout<<"time["<<i<<"]:"<<time[i]<<endl; 138 if(time[i]==time[i-1])continue; 139 for(int j=1;j<=n;j++) 140 { 141 if(cust[j].start<=time[i-1]&&cust[j].last>=time[i]) 142 add(j,n+i,m*(time[i]-time[i-1])); 143 } 144 add(n+i,t,m*(time[i]-time[i-1])); 145 } 146 //for(int i=0;i<ent;i++) 147 //if(edge[i].f)cout<<"s:"<<edge[i].s<<" t:"<<edge[i].t<<" f:"<<edge[i].f<<endl; 148 if(sum==dinic(s,t)) 149 printf("Yes\n"); 150 else printf("No\n"); 151 } 152 return 0; 153 }
2.poj3469
题意:一台双核电脑,给你多个任务,分别给出每个任务在第一个核和第二个核上运行的消耗。后面的m行输入是给出两个任务在两个不同核上运行需要付出的额外消耗。
建图:把每个任务作为节点,在超级源点与任务间的连一条边,其容量为给任务在核1上运行的消耗,在该任务节点与超级汇点之间连一条边,容量为该任务在核2上运行的消耗。
在任务之间连接无向边,容量为两个任务不在同一核上运行的额外消耗。
这题巧就巧在这句:在任务之间连接无向边,容量为两个任务不在同一核上运行的额外消耗。表示不是很理解,如果有大神在跪求带我装逼带我飞n(*≧▽≦*)n
代码:
1 #include<iostream> 2 #include<queue> 3 #include<cstring> 4 #include<cstdio> 5 #include<climits> 6 #define MAXE 1641000 7 #define MAXP 20010 8 #define Max(a,b) a>b?a:b 9 #define Min(a,b) a<b?a:b 10 using namespace std; 11 struct Edge 12 { 13 int s,t,f,next; 14 } edge[MAXE]; 15 int head[MAXP]; 16 int cur[MAXP]; 17 int pre[MAXP]; 18 int stack[MAXE]; 19 int used[MAXP]; 20 int ent; 21 int n,m,s,t; 22 int num; 23 void add(int start,int last,int f) 24 { 25 edge[ent].s=start; 26 edge[ent].t=last; 27 edge[ent].f=f; 28 edge[ent].next=head[start]; 29 head[start]=ent++; 30 edge[ent].s=last; 31 edge[ent].t=start; 32 edge[ent].f=0; 33 edge[ent].next=head[last]; 34 head[last]=ent++; 35 } 36 bool bfs(int S,int T) 37 { 38 memset(pre,-1,sizeof(pre)); 39 pre[S]=0; 40 queue<int>q; 41 q.push(S); 42 while(!q.empty()) 43 { 44 int temp=q.front(); 45 q.pop(); 46 for(int i=head[temp]; i!=-1; i=edge[i].next) 47 { 48 int temp2=edge[i].t; 49 if(pre[temp2]==-1&&edge[i].f) 50 { 51 pre[temp2]=pre[temp]+1; 52 q.push(temp2); 53 } 54 } 55 } 56 return pre[T]!=-1; 57 } 58 int dinic(int start,int last) 59 { 60 int flow=0,now; 61 while(bfs(start,last)) 62 { 63 int top=0; 64 memcpy(cur,head,sizeof(head)); 65 int u=start; 66 while(1) 67 { 68 if(u==last)//如果找到终点结束对中间路径进行处理并计算出该流 69 { 70 int minn=INT_MAX; 71 for(int i=0; i<top; i++) 72 { 73 if(minn>edge[stack[i]].f) 74 { 75 minn=edge[stack[i]].f; 76 now=i; 77 } 78 } 79 for(int i=0;i<top;i++) 80 { 81 edge[stack[i]].f-=minn; 82 edge[stack[i]^1].f+=minn; 83 } 84 flow+=minn; 85 top=now; 86 u=edge[stack[top]].s; 87 } 88 for(int i=cur[u]; i!=-1; cur[u]=i=edge[i].next) //找出从u点出发能到的边 89 if(edge[i].f&&pre[edge[i].t]==pre[u]+1) 90 break; 91 if(cur[u]==-1)//如果从该点未找到可行边,将该点标记并回溯 92 { 93 if(top==0)break; 94 pre[u]=-1; 95 u=edge[stack[--top]].s; 96 } 97 else//如果找到了继续运行 98 { 99 stack[top++]=cur[u]; 100 u=edge[cur[u]].t; 101 } 102 } 103 } 104 return flow; 105 } 106 int main() 107 { 108 while(~scanf("%d%d",&n,&m)) 109 { 110 memset(head,-1,sizeof(head)); 111 ent=0; 112 s=0;t=n+1; 113 int cost1,cost2; 114 for(int i=1;i<=n;i++) 115 { 116 scanf("%d%d",&cost1,&cost2); 117 add(s,i,cost1); 118 add(i,t,cost2); 119 } 120 int u,v,cost; 121 for(int i=1;i<=m;i++) 122 { 123 scanf("%d%d%d",&u,&v,&cost); 124 add(u,v,cost); 125 add(v,u,cost); 126 } 127 printf("%d\n",dinic(s,t)); 128 } 129 return 0; 130 }
3.hdu3061
中文题,思路就是最大权闭合图(妈蛋我竟然一直没看出来,没活路了,不管什么算法不刷题果然都特么不行呀/(ㄒoㄒ)/~~)
代码:
1 #include<iostream> 2 #include<algorithm> 3 #include<queue> 4 #include<cstring> 5 #include<cstdio> 6 #include<climits> 7 #define MAXE 250000 8 #define MAXP 500 9 #define Max(a,b) a>b?a:b 10 #define Min(a,b) a<b?a:b 11 using namespace std; 12 struct Edge 13 { 14 int s,t,f,next; 15 } edge[MAXE]; 16 struct Cust 17 { 18 int start,last,stay; 19 }cust[MAXP]; 20 int head[MAXP]; 21 int time[MAXP*2]; 22 int stay[MAXP]; 23 int cur[MAXP]; 24 int pre[MAXP]; 25 int stack[MAXE]; 26 int used[MAXP]; 27 int ent; 28 int n,m,s,t; 29 int num; 30 void add(int start,int last,int f) 31 { 32 edge[ent].s=start; 33 edge[ent].t=last; 34 edge[ent].f=f; 35 edge[ent].next=head[start]; 36 head[start]=ent++; 37 edge[ent].s=last; 38 edge[ent].t=start; 39 edge[ent].f=0; 40 edge[ent].next=head[last]; 41 head[last]=ent++; 42 } 43 bool bfs(int S,int T) 44 { 45 memset(pre,-1,sizeof(pre)); 46 pre[S]=0; 47 queue<int>q; 48 q.push(S); 49 while(!q.empty()) 50 { 51 int temp=q.front(); 52 q.pop(); 53 for(int i=head[temp]; i!=-1; i=edge[i].next) 54 { 55 int temp2=edge[i].t; 56 if(pre[temp2]==-1&&edge[i].f) 57 { 58 pre[temp2]=pre[temp]+1; 59 q.push(temp2); 60 } 61 } 62 } 63 return pre[T]!=-1; 64 } 65 int dinic(int start,int last) 66 { 67 int flow=0,now; 68 while(bfs(start,last)) 69 { 70 int top=0; 71 memcpy(cur,head,sizeof(head)); 72 int u=start; 73 while(1) 74 { 75 if(u==last)//如果找到终点结束对中间路径进行处理并计算出该流 76 { 77 int minn=INT_MAX; 78 for(int i=0; i<top; i++) 79 { 80 if(minn>edge[stack[i]].f) 81 { 82 minn=edge[stack[i]].f; 83 now=i; 84 } 85 } 86 for(int i=0;i<top;i++) 87 { 88 edge[stack[i]].f-=minn; 89 edge[stack[i]^1].f+=minn; 90 } 91 flow+=minn; 92 top=now; 93 u=edge[stack[top]].s; 94 } 95 for(int i=cur[u]; i!=-1; cur[u]=i=edge[i].next) //找出从u点出发能到的边 96 if(edge[i].f&&pre[edge[i].t]==pre[u]+1) 97 break; 98 if(cur[u]==-1)//如果从该点未找到可行边,将该点标记并回溯 99 { 100 if(top==0)break; 101 pre[u]=-1; 102 u=edge[stack[--top]].s; 103 } 104 else//如果找到了继续运行 105 { 106 stack[top++]=cur[u]; 107 u=edge[cur[u]].t; 108 } 109 } 110 } 111 return flow; 112 } 113 int main() 114 { 115 while(~scanf("%d%d",&n,&m)) 116 { 117 memset(head,-1,sizeof(head)); 118 ent=0;s=0;t=n+1; 119 int cost,sum=0; 120 for(int i=1;i<=n;i++) 121 { 122 scanf("%d",&cost); 123 if(cost>0) 124 { 125 add(s,i,cost); 126 sum+=cost; 127 } 128 else 129 add(i,t,-cost); 130 } 131 for(int i=1;i<=m;i++) 132 { 133 int u,v; 134 scanf("%d%d",&u,&v); 135 add(u,v,INT_MAX); 136 } 137 printf("%d\n",sum-dinic(s,t)); 138 } 139 return 0; 140 }
网络流题目汇集(注:题意翻译以及思路基本都是摘录的别人的(虽然也许有的题目会是自己完全独立做出来的,但是题解一般都不会是自己的,人懒没办法))
标签:
原文地址:http://www.cnblogs.com/lthb/p/4504164.html