网络流建图总结

 

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 */
View Code

 

P2766 最长不下降子序列问题

  1. 计算其最长不下降子序列的长度 ss。
  2. 如果每个元素只允许使用一次,计算从给定的序列中最多可取出多少个长度为 ss 的不下降子序列。
  3. 如果允许在取出的序列中多次使用 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 */
View Code

 

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 */
View Code

 

posted @ 2020-11-23 09:06  Libra_Glow  阅读(109)  评论(0)    收藏  举报