1266: [AHOI2006]上学路线routebzoj

最短路+最小割

/**************************************************************
    Problem: 1266
    User: lxy8584099
    Language: C++
    Result: Accepted
    Time:2708 ms
    Memory:6744 kb
****************************************************************/
 
/*
    n=500 故意给这么小 就往floyd方向考虑
    先求出最短路 如果对于一条路径有 d 1,i + d i,j +d j,n == d 1,n
    可知 i->j一定是某一最短路上的边 
    于是吧所有这些边提取出来 求最小割即可!
    NOTE: 注意边的去重
*/
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=505,M=125000;
struct road 
{
    int u,v,d,c; road(){}
    road(int _u,int _v,int _d,int _c)
        {u=_u,v=_v,d=_d,c=_c;}
} r[M];
struct pp {int v,nxt,c;} e[M<<1];
int head[N],dep[N],n,m,tot=1,d[N][N],st,ed,tax[N],cur[N];
inline int min(int a,int b) {return a>b?b:a;}
inline void add(int u,int v,int c)
{
    e[++tot].nxt=head[u];head[u]=tot;e[tot].v=v;e[tot].c=c;
}
inline void bfs()
{
    queue < int > q; q.push(ed);
    tax[dep[ed]=1]++;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int j=head[u];j;j=e[j].nxt)
        {
            int v=e[j].v;if(dep[v]) continue;
            tax[dep[v]=dep[u]+1]++; q.push(v);
        }
    }
}
inline int dfs(int u,int flow)
{
    if(u==ed) return flow;
    int s=0,val;
    for(int&j=cur[u];j;j=e[j].nxt)
    {
        int v=e[j].v,c=e[j].c;
        if(dep[v]+1==dep[u]&&c>0)
        {
            s+=(val=dfs(v,min(c,flow-s)));
            e[j].c-=val;e[j^1].c+=val;
            if(s==flow) return s;
        }
    }
    --tax[dep[u]];
    if(tax[dep[u]]==0) dep[st]=n+1;
    tax[++dep[u]]++; return s;
     
}
int main()
{
    memset(d,0x3f,sizeof(d));
    scanf("%d%d",&n,&m); st=1; ed=n;
    for(int i=1;i<=n;i++) d[i][i]=0;
    for(int i=1,u,v,t,c;i<=m;i++)
    {
        scanf("%d%d%d%d",&u,&v,&t,&c);
        r[i]=road(u,v,t,c);
        d[u][v]=d[v][u]=min(d[u][v],t);
    }
    for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
        d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
    for(int i=1;i<=m;i++)
    {
        int u=r[i].u,v=r[i].v,w=r[i].d,c=r[i].c;
        if(u==v) continue;
        if(d[1][u]+w+d[v][n]==d[1][n])
            add(u,v,c),add(v,u,0);
        if(d[1][v]+w+d[u][n]==d[1][n]) 
            add(v,u,c),add(u,v,0);
    } int res=0;
    bfs(); while(dep[st]<=n)
    {
        memcpy(cur,head,sizeof(head));
        res+=dfs(st,23333333);
    }
    printf("%d\n%d\n",d[1][n],res);
    return 0;
}

 

转载于:https://www.cnblogs.com/lxy8584099/p/10448706.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值