网络流建图总结
P2065 [TJOI2011]卡片
桌子上现在有m张蓝色卡片和n张红色卡片,每张卡片上有一个大于1的整数。现在你要从桌子上拿走一些卡片,分若干次拿。每次只能拿走一组卡片:这组卡片颜色不同,并且两张卡片上面的数字的最大公约数大于1。问:最多可以从桌上拿走多少张卡片。
思路:直接建图应该是可以的,但是出题人特意卡了直接建图的,我们需要考虑怎么减少建图的边数。考虑 “最大公约数大于1” 这个条件,我们可以把他们的质因子筛出来,因为所有数的质因子个数比较小,**我们可以向质因子连边**,以质因子为中转站。这样连边条数为 n*( 质因子数量 + 1 ) + m * ( 质因子数量 + 1 )
1 //#pragma GCC optimize(2) 2 #include<cstdio> 3 #include<iostream> 4 #include<string> 5 #include<cstring> 6 #include<map> 7 #include<cmath> 8 #include<cctype> 9 #include<vector> 10 #include<set> 11 #include<queue> 12 #include<algorithm> 13 #include<sstream> 14 #include<ctime> 15 #include<cstdlib> 16 #define X first 17 #define Y second 18 #define L (u<<1) 19 #define R (u<<1|1) 20 #define pb push_back 21 #define mk make_pair 22 #define Mid (tr[u].l+tr[u].r>>1) 23 #define Len(u) (tr[u].r-tr[u].l+1) 24 #define random(a,b) ((a)+rand()%((b)-(a)+1)) 25 #define db puts("---") 26 using namespace std; 27 28 void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } 29 void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } 30 void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); } 31 32 typedef long long LL; 33 typedef unsigned long long ULL; 34 typedef pair<int,int> PII; 35 36 const int N=10010,M=N*N,mod=1e9+7,INF=0x3f3f3f3f; 37 const double eps=1e-6; 38 39 int n,m,S,T; 40 int a[N],b[N]; 41 int e[M],ne[M],w[M],h[N],hs[N],idx; 42 int depth[N],tot; 43 map<int,int>mp; 44 45 void add(int a,int b,int c) 46 { 47 e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; 48 e[idx]=a,w[idx]=0,ne[idx]=h[b],h[b]=idx++; 49 } 50 51 bool bfs() 52 { 53 queue<int>q; q.push(S); 54 memset(depth,-1,sizeof (depth)); 55 depth[S]=0; hs[S]=h[S]; 56 while(q.size()) 57 { 58 int u=q.front(); q.pop(); 59 for(int i=h[u];~i;i=ne[i]) 60 { 61 int ver=e[i]; 62 if(depth[ver]==-1&&w[i]) 63 { 64 depth[ver]=depth[u]+1; 65 hs[ver]=h[ver]; 66 if(ver==T) return true; 67 q.push(ver); 68 } 69 } 70 } 71 return false; 72 } 73 74 int dfs(int u,int flow) 75 { 76 if(u==T) return flow; 77 int d=flow; 78 for(int i=hs[u];~i;i=ne[i]) 79 { 80 hs[u]=i; int ver=e[i]; 81 if(depth[ver]==depth[u]+1&&w[i]) 82 { 83 int v=dfs(ver,min(w[i],d)); 84 if(!v) depth[ver]=-1; 85 d-=v; w[i]-=v; w[i^1]+=v; 86 if(!d) break; 87 } 88 } 89 return flow-d; 90 } 91 92 int dinic() 93 { 94 int ans=0,flow; 95 while(bfs()) while(flow=dfs(S,INF)) ans+=flow; 96 return ans; 97 } 98 99 int get(int x) 100 { 101 if(!mp.count(x)) return mp[x]=++tot; 102 else return mp[x]; 103 } 104 105 void divide(int x,int id,int flow) 106 { 107 for(int i=2;i<=x/i;i++) 108 if(x%i==0) 109 { 110 if(flow==1) add(id,get(i),flow); 111 else add(get(i),id,flow); 112 while(x%i==0) x/=i; 113 } 114 if(x>1) 115 { 116 if(flow==1) add(id,get(x),flow); 117 else add(get(x),id,flow); 118 } 119 } 120 121 int main() 122 { 123 // ios::sync_with_stdio(false); 124 // cin.tie(0); 125 126 int _; 127 while(scanf("%d",&_)!=EOF) 128 { 129 while(_--) 130 { 131 scanf("%d%d",&n,&m); tot=n+m+1; mp.clear(); 132 memset(h,-1,sizeof(h)); 133 idx=0; S=0,T=n+m+1; 134 for(int i=1;i<=n;i++) 135 { 136 scanf("%d",&a[i]); 137 divide(a[i],i,1); 138 } 139 for(int i=1;i<=m;i++) 140 { 141 scanf("%d",&b[i]); 142 divide(b[i],i+n,INF); 143 } 144 for(int i=1;i<=n;i++) add(S,i,1); 145 for(int i=1;i<=m;i++) add(i+n,T,1); 146 printf("%d\n",dinic()); 147 } 148 } 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 return 0; 169 } 170 /* 171 172 */
P2766 最长不下降子序列问题
- 计算其最长不下降子序列的长度 ss。
- 如果每个元素只允许使用一次,计算从给定的序列中最多可取出多少个长度为 ss 的不下降子序列。
- 如果允许在取出的序列中多次使用 x_1x1 和 x_nxn(其他元素仍然只允许使用一次),则从给定序列中最多可取出多少个不同的长度为 ss 的不下降子序列。
思路:主要是用到拆点的小技巧,对于每个元素只能用一次的条件,我们可以把每个点拆成一个入点一个出点即可。对于第三问只需要把第二问第一个点和最后一个点的容量改为INF即可。、
1 //#pragma GCC optimize(2) 2 #include<cstdio> 3 #include<iostream> 4 #include<string> 5 #include<cstring> 6 #include<map> 7 #include<cmath> 8 #include<cctype> 9 #include<vector> 10 #include<set> 11 #include<queue> 12 #include<algorithm> 13 #include<sstream> 14 #include<ctime> 15 #include<cstdlib> 16 #define X first 17 #define Y second 18 #define L (u<<1) 19 #define R (u<<1|1) 20 #define pb push_back 21 #define mk make_pair 22 #define Mid (tr[u].l+tr[u].r>>1) 23 #define Len(u) (tr[u].r-tr[u].l+1) 24 #define random(a,b) ((a)+rand()%((b)-(a)+1)) 25 #define db puts("---") 26 using namespace std; 27 28 void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } 29 void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } 30 void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); } 31 32 typedef long long LL; 33 typedef unsigned long long ULL; 34 typedef pair<int,int> PII; 35 36 const int N=100010,M=N*2,mod=1e9+7,INF=0x3f3f3f3f; 37 const double eps=1e-6; 38 39 int n,m,ans=1,S,T; 40 int f[N],a[N]; 41 int e[M],ne[M],w[M],h[N],idx; 42 int hs[N],depth[N]; 43 44 void add(int a,int b,int c) 45 { 46 e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; 47 e[idx]=a,w[idx]=0,ne[idx]=h[b],h[b]=idx++; 48 } 49 50 bool bfs() 51 { 52 queue<int>q; q.push(S); hs[S]=h[S]; 53 memset(depth,-1,sizeof(depth)); depth[S]=0; 54 while(q.size()) 55 { 56 int u=q.front(); q.pop(); 57 for(int i=h[u];~i;i=ne[i]) 58 { 59 int ver=e[i]; 60 if(depth[ver]==-1&&w[i]) 61 { 62 depth[ver]=depth[u]+1; 63 hs[ver]=h[ver]; 64 if(ver==T) return true; 65 q.push(ver); 66 } 67 } 68 } 69 return false; 70 } 71 72 int dfs(int u,int flow) 73 { 74 if(u==T) return flow; 75 int d=flow; 76 for(int i=hs[u];~i;i=ne[i]) 77 { 78 int ver=e[i]; hs[u]=i; 79 if(depth[ver]==depth[u]+1&&w[i]) 80 { 81 int v=dfs(ver,min(d,w[i])); 82 if(!v) depth[ver]=-1; 83 d-=v; w[i]-=v; w[i^1]+=v; 84 if(!d) break; 85 } 86 } 87 return flow-d; 88 } 89 90 int dinic() 91 { 92 int ans=0,flow; 93 while(bfs()) while(flow=dfs(S,INF)) ans+=flow; 94 return ans; 95 } 96 97 int main() 98 { 99 // ios::sync_with_stdio(false); 100 // cin.tie(0); 101 102 memset(h,-1,sizeof(h)); 103 scanf("%d",&n); 104 for(int i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=1; 105 S=0,T=n*2+1; 106 for(int i=1;i<=n;i++) add(i,i+n,1); 107 for(int i=1;i<=n;i++) 108 { 109 for(int j=1;j<i;j++) if(a[j]<=a[i]) f[i]=max(f[i],f[j]+1),ans=max(ans,f[i]); 110 for(int j=1;j<i;j++) if(a[j]<=a[i]&&f[j]+1==f[i]) add(j+n,i,1); 111 } 112 for(int i=1;i<=n;i++) if(f[i]==1) add(S,i,1); else if(f[i]==ans) add(i+n,T,1); 113 printf("%d\n",ans); 114 if(ans==1) printf("%d\n%d\n",n,n); 115 else 116 { 117 118 int res=dinic(); 119 printf("%d\n",res); 120 for(int i=0;i<idx;i+=2) 121 { 122 int a=e[i^1],b=e[i]; 123 if(a==S&&b==1) w[i]=INF; 124 else if(a==1&&b==n+1) w[i]=INF; 125 else if(a==n&&b==n+n) w[i]=INF; 126 else if(a==n+n&&b==T) w[i]=INF; 127 } 128 printf("%d\n",res+dinic()); 129 } 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 return 0; 149 } 150 /* 151 152 */
P2762 太空飞行计划问题
配置仪器 I_kIk 的费用为 c_kck 美元。实验 E_jEj 的赞助商已同意为该实验结果支付 p_jpj 美元。W 教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部费用的差额。
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
思路:最大权闭合子图的模板题,每个实验能得到收益的条件是配置一定费用的仪器,我们只需要按照 S->实验->仪器->T 建图即可。 答案为 tot - dinic ,tot为正权边权值和。
输出要选那个的时候,只需要从 S dfs 一遍,能到的点就是选的实验号,不能到的就是仪器号。
1 //#pragma GCC optimize(2) 2 #include<cstdio> 3 #include<iostream> 4 #include<string> 5 #include<cstring> 6 #include<map> 7 #include<cmath> 8 #include<cctype> 9 #include<vector> 10 #include<set> 11 #include<queue> 12 #include<algorithm> 13 #include<sstream> 14 #include<ctime> 15 #include<cstdlib> 16 #define X first 17 #define Y second 18 #define L (u<<1) 19 #define R (u<<1|1) 20 #define pb push_back 21 #define mk make_pair 22 #define Mid (tr[u].l+tr[u].r>>1) 23 #define Len(u) (tr[u].r-tr[u].l+1) 24 #define random(a,b) ((a)+rand()%((b)-(a)+1)) 25 #define db puts("---") 26 using namespace std; 27 28 void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } 29 void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } 30 void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); } 31 32 typedef long long LL; 33 typedef unsigned long long ULL; 34 typedef pair<int,int> PII; 35 36 const int N=1000010,M=N*2,mod=1e9+7,INF=0x3f3f3f3f; 37 const double eps=1e-6; 38 39 int n,m,S,T; 40 int e[M],ne[M],w[M],h[N],hs[N],idx; 41 int depth[N]; 42 bool st[N]; 43 44 void add(int a,int b,int c) 45 { 46 e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; 47 e[idx]=a,w[idx]=0,ne[idx]=h[b],h[b]=idx++; 48 } 49 50 bool bfs() 51 { 52 queue<int>q; q.push(S); hs[S]=h[S]; 53 memset(depth,-1,sizeof(depth)); depth[S]=0; 54 while(q.size()) 55 { 56 int u=q.front(); q.pop(); 57 for(int i=h[u];~i;i=ne[i]) 58 { 59 int ver=e[i]; 60 if(depth[ver]==-1&&w[i]) 61 { 62 depth[ver]=depth[u]+1; 63 hs[ver]=h[ver]; 64 if(ver==T) return true; 65 q.push(ver); 66 } 67 } 68 } 69 return false; 70 } 71 72 int dfs(int u,int flow) 73 { 74 if(u==T) return flow; 75 int d=flow; 76 for(int i=hs[u];~i;i=ne[i]) 77 { 78 int ver=e[i]; hs[u]=i; 79 if(depth[ver]==depth[u]+1&&w[i]) 80 { 81 int v=dfs(ver,min(d,w[i])); 82 if(!v) depth[ver]=-1; 83 d-=v; w[i]-=v; w[i^1]+=v; 84 if(!d) break; 85 } 86 } 87 return flow-d; 88 } 89 90 int dinic() 91 { 92 int ans=0,flow; 93 while(bfs()) while(flow=dfs(S,INF)) ans+=flow; 94 return ans; 95 } 96 97 void dfs(int u) 98 { 99 for(int i=h[u];~i;i=ne[i]) 100 { 101 int ver=e[i]; 102 if(st[ver]) continue; 103 if(w[i]) st[ver]=1,dfs(ver); 104 } 105 } 106 107 int main() 108 { 109 // ios::sync_with_stdio(false); 110 // cin.tie(0); 111 112 memset(h,-1,sizeof(h)); idx=0; 113 scanf("%d%d",&m,&n); S=0; T=n+m+1; 114 getchar(); int tot=0; 115 for(int i=1;i<=m;i++) 116 { 117 string s; getline(cin,s); 118 int x; stringstream ss(s); 119 ss>>x; add(S,i,x); tot+=x; 120 while(ss>>x) add(i,x+m,INF); 121 } 122 for(int i=1;i<=n;i++) 123 { 124 int x; scanf("%d",&x); 125 add(i+m,T,x); 126 } 127 int ans=dinic(); 128 st[S]=1; dfs(S); 129 for(int i=1;i<=m;i++) if(st[i]) printf("%d ",i); puts(""); 130 for(int i=m+1;i<=m+n;i++) if(st[i]) printf("%d ",i-m); puts(""); 131 printf("%d\n",tot-ans); 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 return 0; 150 } 151 /* 152 153 */

浙公网安备 33010602011771号