loj6045 「雅礼集训 2017 Day8」价
我们考虑最小割。
我一开始觉得是裸的最小割,就直接S到每个减肥药连up+p[i]的边,减肥药到药材连inf边,药材到T连up,然后得到了40分的好成绩。
之后我发现这是一个假的最小割,最小割割的是代价或者得不到的收益,上面说的这种建图左边割掉的是收益,右边割掉的是代价,然后当然就gg了。
所以我们把p取相反数,因为有负权,我们在给所有边加上一个UP,之后就可以直接建图最小割了。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 #define UP 2000000 8 #define inf 0x7fffffff 9 #define N 666 10 using namespace std; 11 int e=2,head[N]; 12 struct edge{ 13 int u,v,f,next; 14 }ed[N*N]; 15 void add(int u,int v,int f){ 16 ed[e].u=u;ed[e].v=v;ed[e].f=f; 17 ed[e].next=head[u];head[u]=e++; 18 ed[e].u=v;ed[e].v=u;ed[e].f=0; 19 ed[e].next=head[v];head[v]=e++; 20 } 21 int n,ans,S,T,dep[N]; 22 bool bfs(){ 23 memset(dep,0,sizeof dep); 24 queue<int> q;q.push(S);dep[S]=1; 25 while(!q.empty()){ 26 int x=q.front();q.pop(); 27 for(int i=head[x];i;i=ed[i].next){ 28 if(ed[i].f&&!dep[ed[i].v]){ 29 dep[ed[i].v]=dep[x]+1; 30 if(ed[i].v==T)return 1; 31 q.push(ed[i].v); 32 } 33 } 34 } 35 return 0; 36 } 37 int dfs(int x,int f){ 38 if(x==T||!f)return f; 39 int ans=0; 40 for(int i=head[x];i;i=ed[i].next){ 41 if(ed[i].f&&dep[ed[i].v]==dep[x]+1){ 42 int nxt=dfs(ed[i].v,min(f,ed[i].f)); 43 ans+=nxt,f-=nxt;ed[i].f-=nxt,ed[i^1].f+=nxt; 44 if(!f)break; 45 } 46 } 47 if(!ans)dep[x]=-1; 48 return ans; 49 } 50 int dinic(){ 51 int ans=0; 52 while(bfs())ans+=dfs(S,inf); 53 return ans; 54 } 55 int main(){ 56 // freopen("test.in","r",stdin); 57 scanf("%d",&n); 58 S=2*n+1;T=S+1; 59 for(int i=1,j,k;i<=n;i++){ 60 scanf("%d",&j); 61 while(j--){ 62 scanf("%d",&k); 63 add(i,n+k,inf); 64 } 65 } 66 for(int i=1,x;i<=n;i++){ 67 scanf("%d",&x); 68 add(S,i,UP-x); 69 add(n+i,T,UP); 70 ans-=UP-x; 71 } 72 ans+=dinic(); 73 printf("%d\n",ans); 74 }
人生如梦亦如幻 朝如晨露暮如霞。