您的位置:首页 > 理论基础 > 计算机网络

BZOJ3876/AHOI2014支线剧情

2016-03-04 22:39 543 查看
思路:

就是每条边要经过最少一次咯,直接上下界网络流把下届设置成1即可,当然一些关于类似汇点的处理方法细节就写着代码里了。详细的可以看别人的。

/*
貌似直接每条边的流量下界设置成1,直接跑最小费用最大流?
好像没有一个明确的汇点
假设增加一个汇点的话 那么结局点要向汇点连多少的边?
索性不要汇点 直接每个点向源点连inf的边来平衡流量
*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
using namespace std;
const int imax=300+9;
const int dmax=imax;
const int bmax=200000+229;
const int inf=100000229;
int n,m,S,T;
int num,head[dmax],from[bmax],to[bmax],inext[bmax],re[bmax],val[bmax];

void iadd(int u,int v,int flow,int nowv){
to[num]=v; from[num]=u; re[num]=flow; val[num]=nowv;
inext[num]=head[u]; head[u]=num++;
}
void add(int u,int v,int flow,int nowv) { iadd(u,v,flow,nowv); iadd(v,u,0,-nowv);}
void iread()
{
scanf("%d",&n);
S=0; T=n+1;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)
{
scanf("%d",&m);
int u=i,v,nowval;
for(int i=1;i<=m;i++)
{
scanf("%d %d",&v,&nowval);
//上下界
add(S,v,1,nowval);
add(u,v,inf,nowval);
}
add(u,T,m,0);
}
for(int i=2;i<=n;i++) add(i,1,inf,0);//代替T->S 的inf
}

int dist[dmax],vis[dmax],pre[dmax];
queue<int> q;
bool spfa()
{
for(int i=S;i<=T;i++) vis[i]=false,dist[i]=inf,pre[i]=-1;
q.push(S); dist[S]=0; vis[S]=1;
while(!q.empty())
{
int u=q.front(); q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=inext[i])
if(re[i] && dist[to[i]]>dist[u]+val[i])
{
pre[to[i]]=i;
dist[to[i]]=dist[u]+val[i];
if(!vis[to[i]]) { vis[to[i]]=1; q.push(to[i]);}
}
}
return dist[T]!=inf;
}

void iwork()
{
int ans=0;
int Maxflow=0;
while(spfa())
{
Maxflow++;
for(int i=T;i!=S;i=from[pre[i]])
{
int k=pre[i];
ans+=val[k];
re[k]-=1; re[k^1]+=1;
}
}
printf("%d\n",ans);
}

int main()
{
iread();
iwork();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息