Party
n
frogs are invited to a tea party. Frogs are conveniently numbered by
1,2,…,n
.
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
m
pairs of frogs who dislike each other. They fight when they are serving the same type of tea.
Luckily, frogs can be divided into
2
groups such that no two frogs in the same group dislike each other.
Frogs like gems. If the
i
-th frog can be paid
wi
gems instead of serving tea, it will not fight with others anymore.
The party manager has to dicide how to serve tea/pay gems to avoid fights, minimizing the total gems paid.
The input consists of multiple tests. For each test:
The first line contains
2
integers
n,m
(
1≤n≤103,0≤m≤104
). The second line contains
n
integers
w1,w2,…,wn
. (
1≤wi≤106
).
The third line contains
n
integers
p1,p2,…,pn
. (
1≤pi≤3
).
pi=1
means the
i
-th frog drinks only black tea.
pi=2
means it drinks only green one, while
pi=3
means it accepts both.
Each of the following
m
lines contains
2
integers
ai,bi
, which denotes frog
ai
and
bi
dislike each other. (
1≤ai,bi≤n
)
Output
For each test, write
1
integer which denotes the minimum total gems paid.
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
省赛过了很久以后我才来看这道题目。然后,yy了几个晚上,终于发现果然是神一样的建图。
题目意思:有n个青蛙喝茶,有些青蛙只能喝红茶,有些青蛙只能喝绿茶,有些青蛙红茶绿茶都可以喝。现在m对青蛙之间有矛盾,有矛盾的青蛙他们不能喝一样的茶,对于每一只青蛙,可以给他w[i]金币,让他不喝茶,他就不会和任何青蛙矛盾了。最少需要给多少金币让他们之间没有矛盾存在。这题里面还有一个很重要的信息,我一开始没有看出来。这句话————“
Luckily, frogs can be divided into
2
groups such that no two frogs in the same group dislike each other.”其实这句话很关键,它的意思就是这个矛盾关系图不存在奇环,是一个2分图。
有了这个条件。我们现在考虑只能喝一种茶的青蛙,红和绿之间即使存在矛盾也没有影响,那么只用考虑红和红,绿和绿之间的矛盾关系。假设不考虑2种都能喝的青蛙,那么红和红,绿和绿都是单独的求出最大点权独立集。由于是2分图,可以很容易求。现在考虑一只2种茶都可以喝的青蛙,这里是关键,我的解法是把这个青蛙拆成2个点,一个点代表他喝红茶,一个点代表他喝绿茶,首先这2个点是不能同时存在,那么必然有边,然后如果这只青蛙和其他只喝红茶的青蛙有矛盾关系,那么对应就是这个青蛙喝红茶和那个青蛙喝红茶不能同时存在,其他情况其实是类似的分析。这样拆点把矛盾关系图建立出来以后,实际上还是一个2分图,现在就是选出最大点权的点让这些点之间不存在矛盾关系。实际上就是点权最大独立集,转换成求点权最小覆盖的模型,就能很轻松的求解了。。。。。想这么久,果然是神建图。其实主要还是拆点。
VIEW CODE
-
- #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;
- }