题解来源:https://webcache.googleusercontent.com/search?q=cache:tXXwdVkVWOEJ:acmrush.appspot.com/2012/01/4/hangzhou2005D.html+&cd=2&hl=zh-CN&ct=clnk&gl=cn
题目大意:
两个公司进行投标,竞争一些channels,每个投标可以包含多个channels,且都有一定的收益,每一个channels只能为其中的一个公司利用,同时保证一个公司给出的投标中选中的channels不会冲突,求出两公司收益总和的最大值。
最多有300000个channels,每个投标最多包含32个channels,每个公司最多有3000个投标。
分析:
这是一个经典的模型,可以用最大流解决。
将每一个投标当成一个结点,A公司的与源点连接,流量为其价值,B公司的与汇点连接,流量亦为其价值,对于A、B公司的投标中有冲突的连一条边,流量为正无穷。最后求出这张图的最小割(即为最大流),表示解决冲突要的最小费用(即被浪费的价值最小),用总价值减去最大流即可。
// File Name: 1212.cpp // Author: Zlbing // Created Time: 2013/4/25 10:05:22 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) const int MAXN=1e4; int d[MAXN]; int C[MAXN][40]; int lenc[MAXN]; string ch; bool use[300050]; struct Edge{ int from,to,cap,flow; }; bool cmp(const Edge& a,const Edge& b){ return a.from < b.from || (a.from == b.from && a.to < b.to); } struct Dinic{ int n,m,s,t; vector<Edge> edges; vector<int> G[MAXN]; bool vis[MAXN]; int d[MAXN]; int cur[MAXN]; void init(int n){ this->n=n; for(int i=0;i<=n;i++)G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap){ edges.push_back((Edge){from,to,cap,0}); edges.push_back((Edge){to,from,0,0});//当是无向图时,反向边容量也是cap,有向边时,反向边容量是0 m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS(){ CL(vis,0); queue<int> Q; Q.push(s); d[s]=0; vis[s]=1; while(!Q.empty()){ int x=Q.front(); Q.pop(); for(int i=0;i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow){ vis[e.to]=1; d[e.to]=d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a){ if(x==t||a==0)return a; int flow=0,f; for(int& i=cur[x];i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){ e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0)break; } } return flow; } //当所求流量大于need时就退出,降低时间 int Maxflow(int s,int t,int need){ this->s=s;this->t=t; int flow=0; while(BFS()){ CL(cur,0); flow+=DFS(s,INF); if(flow>need)return flow; } return flow; } //最小割割边 vector<int> Mincut(){ BFS(); vector<int> ans; for(int i=0;i<edges.size();i++){ Edge& e=edges[i]; if(vis[e.from]&&!vis[e.to]&&e.cap>0)ans.push_back(i); } return ans; } void Reduce(){ for(int i = 0; i < edges.size(); i++) edges[i].cap -= edges[i].flow; } void ClearFlow(){ for(int i = 0; i < edges.size(); i++) edges[i].flow = 0; } }; bool conflict(int a,int b) { REP(i,0,lenc[a]) if(use[C[a][i]])return true; return false; } Dinic solver; int main() { int T; scanf("%d",&T); for(int cas=0;cas<T;cas++) { if(!cas) printf("Case %d:\n",cas+1); else printf("\nCase %d:\n",cas+1); int n,m; scanf("%d",&n); int s=0; CL(lenc,0); CL(C,0); CL(d,0); int sum=0; solver.init(n+3000+1); REP(i,1,n) { scanf("%d",&d[i]); sum+=d[i]; getline(cin,ch); int len=ch.size(); REP(j,1,len-1) { if(ch[j]==' ') lenc[i]++; else C[i][lenc[i]]=C[i][lenc[i]]*10+ch[j]-'0'; } solver.AddEdge(s,i,d[i]); } scanf("%d",&m); int t=n+m+1; REP(i,n+1,m+n) { scanf("%d",&d[i]); sum+=d[i]; getline(cin,ch); int len=ch.size(); CL(use,false) REP(j,1,len-1) { if(ch[j]==' ') { use[C[i][lenc[i]]]=true; lenc[i]++; } else C[i][lenc[i]]=C[i][lenc[i]]*10+ch[j]-'0'; } use[C[i][lenc[i]]]=true; solver.AddEdge(i,t,d[i]); REP(j,1,n) { if(conflict(j,i)) { solver.AddEdge(j,i,INF); } } } int cnt=solver.Maxflow(s,t,INF); printf("%d\n",sum-cnt); } return 0; }