Magic Potion(最大流,跑两遍网络流或者加一个中转点)

Magic Potion

http://codeforces.com/gym/101981/attachments/download/7891/20182019-acmicpc-asia-nanjing-regional-contest-en.pdf

 

从源点到英雄分别拉容量为1和2的边,跑两遍网络流,判断两次的大小和k的大小

  1 #include<iostream>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<cstdio>
  6 #include<algorithm>
  7 #include<queue>
  8 #include<vector>
  9 #include<set>
 10 
 11 #define maxn 500005
 12 #define MAXN 500005
 13 #define mem(a,b) memset(a,b,sizeof(a))
 14 const int N=200005;
 15 const int M=200005;
 16 const int INF=0x3f3f3f3f;
 17 using namespace std;
 18 int n;
 19 struct Edge{
 20     int v,next;
 21     int cap,flow;
 22 }edge[MAXN*20];//注意这里要开的够大。。不然WA在这里真的想骂人。。问题是还不报RE。。
 23 int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN];
 24 int cnt=0;//实际存储总边数
 25 void isap_init()
 26 {
 27     cnt=0;
 28     memset(pre,-1,sizeof(pre));
 29 }
 30 void isap_add(int u,int v,int w)//加边
 31 {
 32     edge[cnt].v=v;
 33     edge[cnt].cap=w;
 34     edge[cnt].flow=0;
 35     edge[cnt].next=pre[u];
 36     pre[u]=cnt++;
 37 }
 38 void add(int u,int v,int w){
 39     isap_add(u,v,w);
 40     isap_add(v,u,0);
 41 }
 42 bool bfs(int s,int t)//其实这个bfs可以融合到下面的迭代里,但是好像是时间要长
 43 {
 44     memset(dep,-1,sizeof(dep));
 45     memset(gap,0,sizeof(gap));
 46     gap[0]=1;
 47     dep[t]=0;
 48     queue<int>q;
 49     while(!q.empty())
 50     q.pop();
 51     q.push(t);//从汇点开始反向建层次图
 52     while(!q.empty())
 53     {
 54         int u=q.front();
 55         q.pop();
 56         for(int i=pre[u];i!=-1;i=edge[i].next)
 57         {
 58             int v=edge[i].v;
 59             if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是从汇点反向bfs,但应该判断正向弧的余量
 60             {
 61                 dep[v]=dep[u]+1;
 62                 gap[dep[v]]++;
 63                 q.push(v);
 64                 //if(v==sp)//感觉这两句优化加了一般没错,但是有的题可能会错,所以还是注释出来,到时候视情况而定
 65                 //break;
 66             }
 67         }
 68     }
 69     return dep[s]!=-1;
 70 }
 71 int isap(int s,int t)
 72 {
 73     if(!bfs(s,t))
 74     return 0;
 75     memcpy(cur,pre,sizeof(pre));
 76     //for(int i=1;i<=n;i++)
 77     //cout<<"cur "<<cur[i]<<endl;
 78     int u=s;
 79     path[u]=-1;
 80     int ans=0;
 81     while(dep[s]<n)//迭代寻找增广路,n为节点数
 82     {
 83         if(u==t)
 84         {
 85             int f=INF;
 86             for(int i=path[u];i!=-1;i=path[edge[i^1].v])//修改找到的增广路
 87                 f=min(f,edge[i].cap-edge[i].flow);
 88             for(int i=path[u];i!=-1;i=path[edge[i^1].v])
 89             {
 90                 edge[i].flow+=f;
 91                 edge[i^1].flow-=f;
 92             }
 93             ans+=f;
 94             u=s;
 95             continue;
 96         }
 97         bool flag=false;
 98         int v;
 99         for(int i=cur[u];i!=-1;i=edge[i].next)
100         {
101             v=edge[i].v;
102             if(dep[v]+1==dep[u]&&edge[i].cap-edge[i].flow)
103             {
104                 cur[u]=path[v]=i;//当前弧优化
105                 flag=true;
106                 break;
107             }
108         }
109         if(flag)
110         {
111             u=v;
112             continue;
113         }
114         int x=n;
115         if(!(--gap[dep[u]]))return ans;//gap优化
116         for(int i=pre[u];i!=-1;i=edge[i].next)
117         {
118             if(edge[i].cap-edge[i].flow&&dep[edge[i].v]<x)
119             {
120                 x=dep[edge[i].v];
121                 cur[u]=i;//常数优化
122             }
123         }
124         dep[u]=x+1;
125         gap[dep[u]]++;
126         if(u!=s)//当前点没有增广路则后退一个点
127         u=edge[path[u]^1].v;
128      }
129      return ans;
130 }
131 
132 struct sair{
133     int num;
134     int mp[505];
135 }mp[505];
136 
137 int main(){
138     std::ios::sync_with_stdio(false);
139     int m,s,t,k;
140     cin>>n>>m>>k;
141     int a,b,c;
142     isap_init();
143     s=0,t=n+m+1;
144     for(int i=1;i<=n;i++) add(s,i,1);
145     for(int i=1;i<=n;i++){
146         cin>>mp[i].num;
147         for(int j=1;j<=mp[i].num;j++){
148             cin>>mp[i].mp[j];
149             add(i,n+mp[i].mp[j],1);
150         }
151     }
152     for(int i=1;i<=m;i++) add(n+i,t,1);
153     int tmp=n;
154     n=t+1;
155     int ans1=isap(s,t);
156 
157     n=tmp;
158     isap_init();
159     for(int i=1;i<=n;i++) add(s,i,2);
160     for(int i=1;i<=n;i++){
161         for(int j=1;j<=mp[i].num;j++){
162             add(i,n+mp[i].mp[j],1);
163         }
164     }
165     for(int i=1;i<=m;i++) add(n+i,t,1);
166     tmp=n;
167     n=t+1;
168     int ans2=isap(s,t);
169     if(ans2-ans1<=k){
170         cout<<ans2<<endl;
171     }
172     else{
173         cout<<ans1+k<<endl;
174     }
175 }
View Code

源点连英雄容量为1,英雄连怪物容量为1,怪物连汇点容量为1

源点连中转点容量为k,中转点连英雄容量为1

  1 #include<iostream>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<cstdio>
  6 #include<algorithm>
  7 #include<queue>
  8 #include<vector>
  9 #include<set>
 10 
 11 #define maxn 500005
 12 #define MAXN 500005
 13 #define mem(a,b) memset(a,b,sizeof(a))
 14 const int N=200005;
 15 const int M=200005;
 16 const int INF=0x3f3f3f3f;
 17 using namespace std;
 18 int n;
 19 struct Edge{
 20     int v,next;
 21     int cap,flow;
 22 }edge[MAXN*20];//注意这里要开的够大。。不然WA在这里真的想骂人。。问题是还不报RE。。
 23 int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN];
 24 int cnt=0;//实际存储总边数
 25 void isap_init()
 26 {
 27     cnt=0;
 28     memset(pre,-1,sizeof(pre));
 29 }
 30 void isap_add(int u,int v,int w)//加边
 31 {
 32     edge[cnt].v=v;
 33     edge[cnt].cap=w;
 34     edge[cnt].flow=0;
 35     edge[cnt].next=pre[u];
 36     pre[u]=cnt++;
 37 }
 38 void add(int u,int v,int w){
 39     isap_add(u,v,w);
 40     isap_add(v,u,0);
 41 }
 42 bool bfs(int s,int t)//其实这个bfs可以融合到下面的迭代里,但是好像是时间要长
 43 {
 44     memset(dep,-1,sizeof(dep));
 45     memset(gap,0,sizeof(gap));
 46     gap[0]=1;
 47     dep[t]=0;
 48     queue<int>q;
 49     while(!q.empty())
 50     q.pop();
 51     q.push(t);//从汇点开始反向建层次图
 52     while(!q.empty())
 53     {
 54         int u=q.front();
 55         q.pop();
 56         for(int i=pre[u];i!=-1;i=edge[i].next)
 57         {
 58             int v=edge[i].v;
 59             if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是从汇点反向bfs,但应该判断正向弧的余量
 60             {
 61                 dep[v]=dep[u]+1;
 62                 gap[dep[v]]++;
 63                 q.push(v);
 64                 //if(v==sp)//感觉这两句优化加了一般没错,但是有的题可能会错,所以还是注释出来,到时候视情况而定
 65                 //break;
 66             }
 67         }
 68     }
 69     return dep[s]!=-1;
 70 }
 71 int isap(int s,int t)
 72 {
 73     if(!bfs(s,t))
 74     return 0;
 75     memcpy(cur,pre,sizeof(pre));
 76     //for(int i=1;i<=n;i++)
 77     //cout<<"cur "<<cur[i]<<endl;
 78     int u=s;
 79     path[u]=-1;
 80     int ans=0;
 81     while(dep[s]<=n)//迭代寻找增广路,n为节点数
 82     {
 83         if(u==t)
 84         {
 85             int f=INF;
 86             for(int i=path[u];i!=-1;i=path[edge[i^1].v])//修改找到的增广路
 87                 f=min(f,edge[i].cap-edge[i].flow);
 88             for(int i=path[u];i!=-1;i=path[edge[i^1].v])
 89             {
 90                 edge[i].flow+=f;
 91                 edge[i^1].flow-=f;
 92             }
 93             ans+=f;
 94             u=s;
 95             continue;
 96         }
 97         bool flag=false;
 98         int v;
 99         for(int i=cur[u];i!=-1;i=edge[i].next)
100         {
101             v=edge[i].v;
102             if(dep[v]+1==dep[u]&&edge[i].cap-edge[i].flow)
103             {
104                 cur[u]=path[v]=i;//当前弧优化
105                 flag=true;
106                 break;
107             }
108         }
109         if(flag)
110         {
111             u=v;
112             continue;
113         }
114         int x=n;
115         if(!(--gap[dep[u]]))return ans;//gap优化
116         for(int i=pre[u];i!=-1;i=edge[i].next)
117         {
118             if(edge[i].cap-edge[i].flow&&dep[edge[i].v]<x)
119             {
120                 x=dep[edge[i].v];
121                 cur[u]=i;//常数优化
122             }
123         }
124         dep[u]=x+1;
125         gap[dep[u]]++;
126         if(u!=s)//当前点没有增广路则后退一个点
127         u=edge[path[u]^1].v;
128      }
129      return ans;
130 }
131 
132 struct sair{
133     int num;
134     int mp[505];
135 }mp[505];
136 
137 int main(){
138     std::ios::sync_with_stdio(false);
139     int m,s,t,k;
140     cin>>n>>m>>k;
141     int a,b,c;
142     isap_init();
143     s=0,t=n+m+1;
144     int ck=t+1;
145     for(int i=1;i<=n;i++)
146         add(s,i,1);
147     add(s,ck,k);
148     for(int i=1;i<=n;i++){
149         cin>>a;
150         for(int j=1;j<=a;j++){
151             cin>>b;
152             add(i,n+b,1);
153         }
154     }
155     for(int i=1;i<=m;i++)
156         add(n+i,t,1);
157     for(int i=1;i<=n;i++){
158         add(ck,i,1);
159     }
160     int tmp=n;
161     n=ck+1;
162     int ans=isap(s,t);
163     cout<<ans<<endl;
164 }
View Code
原文地址:https://www.cnblogs.com/Fighting-sh/p/9986094.html