BZOJ1877(洛谷P2153)[SDOI2009]晨跑

来源:互联网 发布:北师大网络远程教育 编辑:程序博客网 时间:2024/05/16 17:12

费用流

BZOJ题目传送门

洛谷题目传送门

考虑这么建图:
①因为每个点只能访问一次,因此考虑进行拆点,把每个点拆成入点x与出点y(1和n除外),在x与y之间建一条容量为1,距离为0的边。
②对于从1开始的点,建一条1–>i.x容量为1的边。
③对于指向n的点,建一条i.y–>n容量为1的边。
④对于其他点u,v,建一条u.y–>v.x容量为1的边。

最后跑一遍费用流即可,最大流的答案即为天数,费用即为路程和。

代码:

#include<cstdio>#include<cstring>#include<algorithm>#define MAXN 400#define MAXM 40000using namespace std;struct edge{    int next,to,dis,v,flow;};struct father{    int x,e;};int n,m,k;int h[MAXN+5],dis[MAXN+5],rem[MAXN+5],que[2*MAXM+5];bool f[MAXN+5];edge ed[2*MAXM+5];father fa[MAXN+5];int spfa(){    memset(f,false,sizeof(f));    memset(dis,0x3f3f3f3f,sizeof(dis));    dis[1]=0; que[1]=1; rem[1]=0x7fffffff;    int r=0,w=1;    while (r<w){        int x=que[++r];        f[x]=false;        for (int i=h[x];~i;i=ed[i].next)            if (ed[i].v>ed[i].flow&&dis[ed[i].to]>dis[x]+ed[i].dis){                int v=ed[i].to;                dis[v]=dis[x]+ed[i].dis;                fa[v].x=x; fa[v].e=i;                rem[v]=min(rem[x],ed[i].v-ed[i].flow);                if (!f[v]){ f[v]=true; que[++w]=v;  }            }    }    if (dis[n]==0x3f3f3f3f) return 0;    return rem[n];}void change(int sum){    int now=n;    while (now!=1){        int e=fa[now].e;        ed[e].flow+=sum; ed[e^1].flow-=sum; now=fa[now].x;    }}void mcmf(){    int ans=0,cst=0;    while (1){        int sum=spfa();        if (!sum) { printf("%d %d\n",ans,cst); return;  }        ans++; cst+=sum*dis[n]; change(sum);    }}void addedge(int x,int y,int z,int w){    ed[k].next=h[x]; ed[k].to=y; ed[k].v=z; ed[k].dis=w; h[x]=k++;    ed[k].next=h[y]; ed[k].to=x; ed[k].v=0; ed[k].dis=-w; h[y]=k++;}int main(){    scanf("%d%d",&n,&m);    memset(h,-1,sizeof(h));    for (int i=1;i<=m;i++){        int u,v,d;        scanf("%d%d%d",&u,&v,&d);        if (u!=1&&v!=n) addedge(u+n,v,1,d);        if (u==1&&v!=n) addedge(u,v,1,d);        if (u!=1&&v==n) addedge(u+n,v,1,d);        if (u==1&&v==n) addedge(u,v,1,d);    }    for (int i=2;i<n;i++)        addedge(i,i+n,1,0);    mcmf();    return 0;}