AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=3511
题目分析:
看上去和前面的人员雇佣以及小M种田都很像。
最小割模型来求最大值,一般都是考虑怎样构图使得满足一个组合能被表示出来,而且当满足一个组合的时候,能产生或失去所需的效益。[割掉的是不要的]
我们将s与1相连,连为INF,这样就不会被割,n向t连边,同理。
因为1和n会有边连接,所以我们才多建出了节点s,t。
然后对于每个点i,s向i连wa[i],i向t连wb[i],这样就满足了第一条性质。
对于ea,eb,ec的弄法,我们就先从s向u和向v连ea/2,从u和v向t连eb/2,然后在uv之间连一条双向的ea/2+eb/2+ec的边。
这样连边就能满足第二条性质了,反正就是脑补一下各种割法,就发现它奥妙重重,十分正确。
然后可以缩一下边,把s->i的边集以及i->t的合并一下[优化一下常数]。
#include<cstdio> #include<cstring> #include<algorithm>using namespace std;const int maxn=10010; const int maxm=40010; const int INF=0x3f3f3f3f;struct Node{int data,next,low; }node[maxm*2+maxn*4];#define now node[point].data #define www node[point].low #define then node[point].nextint n,m,cnt; int s,t,ans; int wa[maxn],wb[maxn]; int stoi[maxn],itot[maxn]; int cur[maxn],head[maxn]; int dis[maxn],que[maxn];void add(int u,int v,int w){node[cnt].data=v;node[cnt].next=head[u];node[cnt].low=w;head[u]=cnt++;node[cnt].data=u;node[cnt].next=head[v];node[cnt].low=0;head[v]=cnt++; }void add2(int u,int v,int w){node[cnt].data=v;node[cnt].next=head[u];node[cnt].low=w;head[u]=cnt++;node[cnt].data=u;node[cnt].next=head[v];node[cnt].low=w;head[v]=cnt++; }bool BFS(){memset(dis,-1,sizeof(dis));int H=0,T=1;que[1]=s;dis[s]=0;while(H<T){H++;for(int point=head[que[H]];point!=-1;point=then)if(www && dis[now]<0){dis[now]=dis[que[H]]+1;que[++T]=now;}}return dis[t]>0; }int dfs(int x,int low){if(x==t) return low;int Low;for(int &point=cur[x];point!=-1;point=then)if(www && dis[now]==dis[x]+1){Low=dfs(now,min(low,www));if(Low){www-=Low,node[point^1].low+=Low;return Low;}}return 0; }int main(){ #ifndef ONLINE_JUDGEfreopen("3511.in","r",stdin);freopen("3511.out","w",stdout); #endifint u,v,Ea,Eb,Ec;scanf("%d%d",&n,&m);t=n+1;for(int i=s;i<=t;i++) head[i]=-1;for(int i=2;i<n;i++) scanf("%d",&wa[i]),stoi[i]+=(wa[i]<<1);for(int i=2;i<n;i++) scanf("%d",&wb[i]),itot[i]+=(wb[i]<<1);for(int i=1;i<=m;i++){scanf("%d%d%d%d%d",&u,&v,&Ea,&Eb,&Ec);add2(u,v,Ea+Eb+(Ec<<1));stoi[u]+=Ea,stoi[v]+=Ea;itot[u]+=Eb,itot[v]+=Eb;}for(int i=1;i<=n;i++)ans+=stoi[i]+itot[i];stoi[1]=itot[n]=INF;for(int i=1;i<=n;i++)add(s,i,stoi[i]),add(i,t,itot[i]);int flag;while(BFS()){memcpy(cur,head,sizeof(head));while(flag=dfs(s,INF))ans-=flag;}ans>>=1;printf("%d",ans);return 0; }