四川省赛G.Party
来源:互联网 发布:淘宝网关键词排名查询 编辑:程序博客网 时间:2024/05/17 02:48
题目链接:http://acm.bnu.edu.cn/v3/contest_show.php?cid=6865#problem/G
题意:n只青蛙,要么只喝绿茶,要么只喝红茶,要么两种茶都能接受,还有m个憎恶关系,互相憎恶的两只青蛙不能喝同一种茶,憎恶关系构成的图保证是一张二分图,当然,你还可以选择花费w[i]的代价删掉某只青蛙。问最少需要花费多少代价。
分析:题目问最小代价,给出的又是憎恶关系,容易想到最小割,关键是建图比较难想。首先,题目保证是二分图,可以对他黑白染色。假设没有两种茶都能喝的青蛙,那么只要对有边的且能喝茶种类相同的青蛙建边,流量连INF,跑最小割即可。现在考虑能喝两种茶的青蛙,假设他是白色的,那么可以将他拆成白红和白绿两个点,显然,白红只可能和黑红连边,白绿只可能和黑绿连边,因此我们可以考虑在左边放白绿/黑红,右侧放白红/黑绿,中间放置被拆成两个点的两种茶都能喝的青蛙,注意两种茶都能喝的青蛙之间可能有憎恶关系,我们把割边的流量设置在拆出的两个点之间,为了能让拆出两个点之间的流量起作用(选择这条边当割边就意味着删掉这只青蛙),需要从拆出的点中右侧的点连向左侧,这样就能保证删除起到了效果,具体还是要看下代码。
#include<bits/stdc++.h>using namespace std;typedef pair<int,int>pi;const int Inf=2e9,Maxn=1020*3,Maxe=320000;int n,m,s,t,ne;int val[Maxn],p[Maxn],col[Maxn],id[Maxn],h[Maxn];int cur[Maxn];vector<int>G1[Maxn];vector<int>G[Maxn];void dfs1(int u,int C){ col[u]=C; for(int i=0;i<G1[u].size();i++) { int v=G1[u][i];if(col[v])continue; dfs1(v,3-C); }}pi e[Maxe];void add(int u,int v,int w){ e[ne]=pi(v,w); G[u].push_back(ne++); e[ne]=pi(u,0); G[v].push_back(ne++);}bool bfs(){ queue<int>q; for(int i=s;i<=t;i++)h[i]=Inf; h[s]=0; q.push(s); while(!q.empty()) { int u=q.front();q.pop(); for(int i=0;i<G[u].size();i++) { int v=e[G[u][i]].first,w=e[G[u][i]].second; if(!w||h[v]!=Inf)continue; h[v]=h[u]+1; q.push(v); } } return h[t]!=Inf;}int dfs(int u,int a){ if(u==t||!a)return a; int ret=0; for(int &i=cur[u];i<G[u].size();i++) { int v=e[G[u][i]].first,w=e[G[u][i]].second; if(h[v]!=h[u]+1||!w)continue; int b=dfs(v,min(a,w)); e[G[u][i]].second-=b; e[G[u][i]^1].second+=b; ret+=b; a-=b; } return ret;}int dinic(){ for(int i=s;i<=t;i++)cur[i]=0; int ret=0; while(bfs()) { for(int i=s;i<=t;i++)cur[i]=0; ret+=dfs(s,Inf); } return ret;}int main(){ while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=n;i++)scanf("%d",val+i); for(int i=1;i<=n;i++)G1[i].clear(); for(int i=1;i<=n;i++)scanf("%d",p+i); for(int i=0;i<m;i++) { int u,v;scanf("%d%d",&u,&v); G1[u].push_back(v); G1[v].push_back(u); } for(int i=1;i<=n;i++)col[i]=0; for(int i=1;i<=n;i++) { if(!col[i])dfs1(i,1); } //for(int i=1;i<=n;i++)printf("%d ",col[i]);puts(""); ne=s=0; t=n+1; for(int i=1;i<=n;i++) { if(p[i]==3) { id[i]=t++; } } for(int i=s;i<=t;i++)G[i].clear(); if(t>=Maxn)while(1); for(int i=1;i<=n;i++) { if(p[i]<3) { if(col[i]==p[i]) { //printf("u=%d\n",i); add(s,i,val[i]); for(int j=0;j<G1[i].size();j++) { int v=G1[i][j]; if(p[v]==3)add(i,v,Inf); else if(p[v]!=col[v])add(i,v,Inf); } } else { add(i,t,val[i]); //if(i==1)printf("t=%d\n",t); for(int j=0;j<G1[i].size();j++) { int v=G1[i][j]; if(p[v]==3)add(id[v],i,Inf); } } } else { add(i,id[i],val[i]); for(int j=0;j<G1[i].size();j++) { int v=G1[i][j]; if(p[v]==3)add(id[v],i,Inf); } } } //for(int i=1;i<=n;i++)printf("%d ",col[i]);puts(""); /* for(int i=s;i<=t;i++) { printf("point%d:\n",i); for(int j=0;j<G[i].size();j++) { printf("to=%d w=%d\n",e[G[i][j]].first,e[G[i][j]].second); } puts(""); } */ printf("%d\n",dinic()); }}
0 0
- 四川省赛G.Party
- 2017四川省省赛G
- 2017四川省赛G题2017
- 2017年四川省赛 -- G题 2017 【容斥定理】
- 四川省赛
- scu oj 4442 Party(2015年四川省acm程序设计竞赛)
- Gym 101097G Party
- 2017四川省赛总结
- POJ 3663 Costume Party G++
- 2015 四川省赛 C. Censor
- 2015 四川省赛 B. Carries
- 2016四川省赛 Floyd-Warshall
- 2016四川省省赛总结
- 2017四川省省赛E
- 2017四川省省赛E
- scu oj 4442 Party(2015年四川省acm程序设计竞赛)★ ★ ★
- scu oj 4442 Party(2015年四川省acm程序设计竞赛)(*)
- 2013 四川省赛暨成都邀请赛 总结
- C# : Socket 接收中文显示乱码的解决办法
- Help library 安装arcobjects for .NET异常问题
- JAVA实现斐波那契数列问题(《剑指offer》)
- (void**)&a
- SCU 4438 Censor (字符串哈希)
- 四川省赛G.Party
- UVA 11292 Dragon of Loowater
- 求n^k的前3位和后3位
- 用递归判断一个数组是否递增 JAVA代码
- nyoj 一种排序 8 (结构体 排序)
- Android 事件处理详解(四) —— Handler和AsyncTask(补充)
- HDU5483求一个图中的最小生成树不能去掉的边的数目
- Spinner
- 对Oracle性能调优的基本方案