您的位置:首页 > 理论基础 > 计算机网络

codeforces gym 100357 J (网络流)

2017-04-30 23:45 363 查看
题目大意

  有n种物品,m种建筑,p个人。 n,m,p∈[1,20]

  每种建筑需要若干个若干种物品来建造。每个人打算建造一种建筑,拥有一些物品。

  主角需要通过交易来建造自己的建筑,交易的前提是对方用多余的物品来换取自己需要的物品。

  询问主角是否能建造成功自己的建筑,并给出方案。  

解题分析

  超级恶心的读入,而且有一组数据的给出方式里没有逗号,和样例所示不同= =

  根据py的性质很容易想到用网络流来做。将每种物品拆成x,y两份。

  若主角多了a物品b件,连一条S到物品a,x部流量为b的边。

  若主角少了a物品b件,连一条物品a,y部到T流量为b的边。

  若某人少了a物品b件,连一条物品a,x部流量为b到该人流量为b的边。

  若某人多了a物品b件,连一条该人到物品a,y部流量为b到该人流量为b的边。  模拟了一次交易的进行。

  再由每个物品的y部向每个物品的x部连一条流量为无穷大的边。  表示交易可以不停的进行。

  跑一遍网络流,如果是满流的话,说明可以成功。

  输出方案则再残量网络上进行一次dfs,将每一次的交易的情况依次输出。

参考程序

#include <bits/stdc++.h>
using namespace std;

#define rep(i,x,y) for (int i=x;i<=y;i++)
//#define DEBUG
const int N=500;
const int INF=2000000000;

int n,m,p,sum,lt
,cur
,S,TT,T,dis
;

struct node{
int u,v,f,nt;
}eg[N*2];

map <string,int> build_number;
map <string,int> res_number;
string res_name
;
string build_name
;
string people_name
;
string my_build;

int build_need

;
int people_has

;

void add(int u,int v,int f)
{
#ifdef DEBUG
cout<<u<<" "<<v<<" "<<f<<endl;
#endif
eg[++sum]=(node){u,v,f,lt[u]}; lt[u]=sum;
eg[++sum]=(node){v,u,0,lt[v]}; lt[v]=sum;
}

bool bfs()
{
memset(dis,0,sizeof(dis));
queue <int> Q;
dis[S]=1; Q.push(S);
while (!Q.empty())
{
int u=Q.front(); Q.pop();
for (int i=lt[u];i;i=eg[i].nt)
{
int v=eg[i].v;
if (eg[i].f && !dis[v])
{
dis[v]=dis[u]+1;
Q.push(v);
}
}
}
return dis[T];
}

int dfs(int u,int flow)
{
if (u==T) return flow;
int res=0,f;
for (int &i=cur[u];i;i=eg[i].nt)
{
int v=eg[i].v;
if (eg[i].f && dis[v]==dis[u]+1)
{
f=dfs(v,min(flow-res,eg[i].f));
res+=f;
eg[i].f-=f; eg[i^1].f+=f;
if (res==flow) break;
}
}
return res;
}

int dinic()
{
int sum=0;
while (bfs())
{
rep(i,S,T) cur[i]=lt[i];
sum+=dfs(S,INF);
}
return sum;
}

void solve(int u,int fa)
{
//cout<<u<<" "<<fa<<endl;
if (u==T) return;
for (int i=lt[u];i;i=eg[i].nt)
if (i%2==0 && eg[i^1].f)
{
int v=eg[i].v;
int times=1;
if (u==S) times=eg[i^1].f;
rep(j,1,times)
{
eg[i^1].f--;
if (u>=n+1 && u<=n+p)
{
//cout<<u-n<<" "<<fa<<" "<<v-n-p<<" "<<v<<endl;
cout<<"trade with "<<people_name[u-n]<<" "<<res_name[fa]<<" for "<<res_name[v-n-p]<<endl;
}
solve(v,u);
}
if (u!=S) break;
}
}

int main()
{
freopen("trading.in","r",stdin);
#ifndef DEBUG
freopen("trading.out","w",stdout);
#endif
char ch;
cin.sync_with_stdio(0);
memset(lt,0,sizeof(lt)); sum=1;
cin>>p>>n>>m;
S=0,TT=n*2+p+1,T=n*2+p+2;
int total=0;
rep(i,1,n)
{
cin>>res_name[i];
res_number[res_name[i]]=i;
}

rep(i,1,m)
{
cin>>build_name[i];
build_number[build_name[i]]=i;
string s;
cin>>s;
for (;;)
{
int x;
cin>>x>>s;
if (s[s.length()-1]==',')
{
s.erase(s.end()-1);
build_need[i][res_number[s]]=x;
}
else
{
build_need[i][res_number[s]]=x;
}
cin.get(ch);
if (ch=='\n') break;
}
}

string s; cin>>s>>s>>s;

if (s[s.length()-1]==',') s.erase(s.end()-1);
my_build=s;
cin.get(ch);
if (ch!='\n')
{
string t; cin>>t;
for (;;)
{
int x; cin>>x>>t;
if (t[t.length()-1]==',')
{
t.erase(t.end()-1);
people_has[1][res_number[t]]=x;
}
else
{
people_has[1][res_number[t]]=x;
}
cin.get(ch);
if (ch=='\n') break;
}
}

rep(i,1,n)
{
int y=people_has[1][i]-build_need[build_number[s]][i];
if (y>0) add(S,i,y);
if (y<0) {add(i+n+p,TT,-y); total+=-y;}
}

add(TT,T,total);

rep(i,2,p)
{
string s; cin>>people_name[i]>>s>>s;
if (s[s.length()-1]==',') s.erase(s.end()-1);
cin.get(ch);
if (ch=='\n') continue;
string t; cin>>t;
for (;;)
{
int x; cin>>x>>t;
if (t[t.length()-1]==',')
{
t.erase(t.end()-1);
people_has[i][res_number[t]]=x;
}
else
{
people_has[i][res_number[t]]=x;
}
cin.get(ch);
//cout<<(int)ch<<endl;
if (cin.fail()) break;
if (ch=='\n') break;
}
rep(j,1,n)
{
//cout<<"\t"<<j<<" "<<people_has[i][j]<<" "<<build_need[build_number[s]][j]<<endl;
int y=people_has[i][j]-build_need[build_number[s]][j];
if (y>0) add(i+n,n+p+j,y);
if (y<0) add(j,i+n,-y);
}
}
rep(i,1,n) add(n+p+i,i,INF);

int x=dinic();

#ifdef DEBUG
cout<<x<<" "<<total<<endl;
#endif
if (x==total) {solve(S,0); cout<<"build "<<my_build<<endl;}
else cout<<"No way"<<endl;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: