scu oj 4442 Party(2015年四川省acm程序设计竞赛)
Party
The tea party has black and green tea in service. Each frog has its own preference. He or she may drink only black/green tea or accept both.
There are
Luckily, frogs can be divided into
Frogs like gems. If the
The party manager has to dicide how to serve tea/pay gems to avoid fights, minimizing the total gems paid.
Input
The input consists of multiple tests. For each test:
The first line contains
The third line contains
Each of the following
Output
For each test, write
Sample Input
2 1
1 1
3 3
1 2
2 1
1 1
2 2
1 2
3 2
2 1 2
1 3 2
1 2
2 3
Sample Output
0
1
1
然后,yy了几个晚上。最终发现果然是神一样的建图。
如今m对青蛙之间有矛盾。有矛盾的青蛙他们不能喝一样的茶,对于每一仅仅青蛙。能够给他w[i]金币。让他不喝茶。他就不会和不论什么青蛙矛盾了。最少须要给多少金币让他们之间没有矛盾存在。这题里面另一个非常重要的信息,我一開始没有看出来。
这句话————“Luckily,
frogs can be divided into
我们如今考虑仅仅能喝一种茶的青蛙,红和绿之间即使存在矛盾也没有影响,那么仅仅用考虑红和红,绿和绿之间的矛盾关系。如果不考虑2种都能喝的青蛙。那么红和红,绿和绿都是单独的求出最大点权独立集。
因为是2分图,能够非常easy求。
如今考虑一仅仅2种茶都能够喝的青蛙。这里是关键,我的解法是把这个青蛙拆成2个点,一个点代表他喝红茶,一个点代表他喝绿茶,首先这2个点是不能同一时候存在。那么必定有边,然后如果这仅仅青蛙和其它仅仅喝红茶的青蛙有矛盾关系。那么相应就是这个青蛙喝红茶和那个青蛙喝红茶不能同一时候存在,其它情况事实上是类似的分析。这样拆点把矛盾关系图建立出来以后,实际上还是一个2分图。如今就是选出最大点权的点让这些点之间不存在矛盾关系。
实际上就是点权最大独立集。转换成求点权最小覆盖的模型,就能非常轻松的求解了。
。。。。想这么久,果然是神建图。事实上主要还是拆点。
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cmath> #include<queue> using namespace std; const int mmax = 2010; const int inf = 0x3fffffff; struct node { int flow; int en; int next; }E[100*mmax]; int p[mmax]; int num; void init() { memset(p,-1,sizeof p); num=0; } void add(int st,int en,int flow) { E[num].en=en; E[num].flow=flow; E[num].next=p[st]; p[st]=num++; E[num].en=st; E[num].flow=0; E[num].next=p[en]; p[en]=num++; } int d[mmax]; int cur[mmax]; bool vis[mmax]; bool bfs(int st,int en) { memset(vis,0,sizeof vis); d[st]=0; vis[st]=1; queue<int>q; q.push(st); while(!q.empty()) { int x=q.front(); q.pop(); for(int i=p[x]; i+1; i=E[i].next) { int v=E[i].en; if(!vis[v]&&E[i].flow) { vis[v]=1; d[v]=d[x]+1; q.push(v); } } } return vis[en]; } int dfs(int st,int en,int flow) { if(st==en||flow==0) return flow; int f=0,dd; for(int &i=cur[st]; i+1;i=E[i].next) { int v=E[i].en; if(d[st]+1==d[v]&&(dd=dfs(v,en,min(flow,E[i].flow)))>0) { E[i].flow-=dd; E[i^1].flow+=dd; flow-=dd; f+=dd; if(flow==0) break; } } return f; } int dinic(int st,int en,int n) { int flow=0; while(bfs(st,en)) { for(int i=0;i<=n;i++) cur[i]=p[i]; flow+=dfs(st,en,inf); } return flow; } vector<int>e[mmax]; int fg[mmax]; int w[mmax]; void dfs(int u) { int SZ=e[u].size(); for(int i=0;i<SZ;i++) { int v=e[u][i]; if(d[v]==-1) { d[v]=d[u]^1; dfs(v); } } } int main() { int n,m; while(~scanf("%d %d",&n,&m)) { for(int i=0;i<mmax;i++) e[i].clear(); for(int i=1;i<=n;i++) scanf("%d",&w[i]); int sum=0; for(int i=1;i<=n;i++) { scanf("%d",&fg[i]); if(fg[i]==3) sum+=w[i]; } for(int i=0;i<m;i++) { int u,v; scanf("%d %d",&u,&v); e[u].push_back(v); e[v].push_back(u); } init(); memset(d,-1,sizeof d); for(int i=1;i<=n;i++) { if(d[i]==-1) { d[i]=0; dfs(i); } } int st=0,en=2*n+1; for(int i=1;i<=n;i++) { if(d[i]==0) { if(fg[i]==1) add(st,i,w[i]); if(fg[i]==2) add(i,en,w[i]); if(fg[i]==3) { add(st,i,w[i]); add(i,i+n,inf); add(i+n,en,w[i]); } } else { if(fg[i]==1) add(i,en,w[i]); if(fg[i]==2) add(st,i,w[i]); if(fg[i]==3) { add(i,en,w[i]); add(st,i+n,w[i]); add(i+n,i,inf); } } } for(int u=1;u<=n;u++) { int Sz=e[u].size(); for(int i=0;i<Sz;i++) { int v=e[u][i]; if(d[u]==0 && d[v]==1) { if( (fg[u]==fg[v]) && (fg[u]!=3) ) { if(fg[u]==1) add(u,v,inf); else add(v,u,inf); } else if( (fg[u]==fg[v]) && (fg[u]==3) ) { add(u,v,inf); add(v+n,u+n,inf); } else if(fg[u]==3 || fg[v]==3 ) { if(fg[u]==3) { if(fg[v]==1) add(u,v,inf); else add(v,u+n,inf); } if(fg[v]==3) { if(fg[u]==1) add(u,v,inf); else add(v+n,u,inf); } } } } } printf("%d\n",dinic(st,en,en)-sum); } return 0; }