标签:
这玩意叫啥来着? 最大权闭合图? 反正是个裸题
于是正常暴力构图,正确性很显然:
假设任务在S一侧,机器在T一侧。
如果任务A在S割且机器B也在S割,那么割掉的是边B-->T,这代表购买机器的代价。
如果任务A在T割且机器B也在T割,那么割掉的是边S-->A,这代表舍弃任务的代价。
如果任务A在S割但机器B在T割,那么割掉的是边A-->B,这代表租用机器的代价。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<queue> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();} while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();} return x*f; } #define maxm 3000010 #define maxn 3010 int n,m,tot; struct EdgeNode{int next,to,cap;}edge[maxm]; int head[maxn],cnt=1; void add(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w;} void insert(int u,int v,int w) {add(u,v,w); add(v,u,0);} #define inf 0x7fffffff int dis[maxn],cur[maxn],S,T; bool bfs() { queue<int>q; for (int i=S; i<=T; i++) dis[i]=-1; q.push(S); dis[S]=0; while (!q.empty()) { int now=q.front(); q.pop(); for (int i=head[now]; i; i=edge[i].next) if (edge[i].cap && dis[edge[i].to]==-1) dis[edge[i].to]=dis[now]+1,q.push(edge[i].to); } return dis[T]!=-1; } int dfs(int x,int low) { if (x==T) return low; int used=0,w; for (int i=cur[x]; i; i=edge[i].next) if (edge[i].cap && dis[edge[i].to]==dis[x]+1) { w=dfs(edge[i].to,min(edge[i].cap,low-used)); edge[i].cap-=w; edge[i^1].cap+=w; used+=w; if (edge[i].cap) cur[x]=i; if (low==used) return used; } if (!used) dis[x]=-1; return used; } int dinic() { int tmp=0; while (bfs()) { for (int i=S; i<=T; i++) cur[i]=head[i]; tmp+=dfs(S,inf); } return tmp; } int main() { n=read(),m=read(); S=0,T=n+m+1; for (int x,y,i=1; i<=n; i++) { x=read(),y=read(); tot+=x; insert(S,i,x); for (int z,c,j=1; j<=y; j++) z=read(),c=read(),insert(i,z+n,c); } for (int x,i=1; i<=m; i++) x=read(),insert(i+n,T,x); printf("%d\n",tot-dinic()); return 0; }
标签:
原文地址:http://www.cnblogs.com/DaD3zZ-Beyonder/p/5618581.html