Marriage Match IV HDU - 3416

点击打开链接

这个题也是看了题解才想到要用最短路和网络流结合的。。

题目要求每次只能走最短路 意思不是走一次最短路就把这条路径删除 然后再找新的最短路即原图的次短路  而是仍然找一条和最开始的最短路长度一样的路径

这样所有构成最短路的边都是可以确定的

反向建图 dis1[n]代表从起点ss到每个点的最短距离 dis2[n]代表从终点ee到每个点的最短距离 对于一条边edge[i] 如果dis1[edge[i].u]+edge[i].w+dis2[edge[i].v]==dis1[ee] 则这条边就在一条最短路上

最后 把起点作源点 终点作汇点 以所有最短路上的边建立网络流模型(边权值为1) 就可以知道 利用所有的这些边可以凑数几条从源点到汇点的增广路

因为边权值是1 所以每条增广路的流量都是1 最终得到的最大流即是增广路条数

 

#include <stdio.h>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 0x3f3f3f3f

struct nodeI
{
    int u;
    int v;
    int w;
};

struct nodeII
{
    int v;
    int w;
    int next;
};

struct nodeIII
{
    friend bool operator < (nodeIII n1,nodeIII n2)
    {
        return n1.w>n2.w;
    }
    int v;
    int w;
};

priority_queue <nodeIII> que;
nodeI gg[100010];
nodeII edge1[100010],edge2[100010],edge3[200010];
int first1[1010],first2[1010],first3[1010],dis1[1010],dis2[1010],book[1010];
int dis[1010],gap[1010],cur[1010],pre[1010];
int n,m,num,ss,ee,ans;

void addedge(int u,int v,int w,nodeII* edge,int* first)
{
    edge[num].v=v;
    edge[num].w=w;
    edge[num].next=first[u];
    first[u]=num++;
    return;
}

void calculate(nodeII* edge,int* first,int* dis,int &s)
{
    nodeIII cur,tem;
    int i,u,v,w;
    while(!que.empty()) que.pop();
    for(i=1;i<=n;i++)
    {
        dis[i]=N;
        book[i]=0;
    }
    tem.v=s,tem.w=0;
    que.push(tem);
    dis[s]=0;
    while(!que.empty())
    {
        cur=que.top();
        que.pop();
        u=cur.v;
        if(book[u]==1) continue;
        book[u]=1;
        for(i=first[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].v,w=edge[i].w;
            if(book[v]==0&&dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                tem.v=v,tem.w=dis[v];
                que.push(tem);
            }
        }
    }
    return;
}

void judge()
{
    int i,u,v,w;
    memset(first3,-1,sizeof(first3));
    num=0;
    for(i=1;i<=m;i++)
    {
        u=gg[i].u,v=gg[i].v,w=gg[i].w;
        if(dis1[u]+w+dis2[v]==dis1[ee])
        {
            addedge(u,v,1,edge3,first3);
            addedge(v,u,0,edge3,first3);
        }
    }
    return;
}

void bfs()
{
    queue <int> que;
    int i,u,v;
    memset(dis,-1,sizeof(dis));
    memset(gap,0,sizeof(gap));
    que.push(ee);
    dis[ee]=0;
    while(!que.empty())
    {
        u=que.front();
        que.pop();
        gap[dis[u]]++;
        for(i=first3[u];i!=-1;i=edge3[i].next)
        {
            v=edge3[i].v;
            if(dis[v]==-1)
            {
                que.push(v);
                dis[v]=dis[u]+1;
            }
        }
    }
    return;
}

void isap()
{
    int j,u,v,w,flow,minn;
    bfs();
    memcpy(cur,first3,sizeof(first3));
    memset(pre,-1,sizeof(pre));
    ans=0,u=ss,flow=N;
    while(dis[ss]<n)
    {
        int &i=cur[u];
        for(;i!=-1;i=edge3[i].next)
        {
            v=edge3[i].v,w=edge3[i].w;
            if(dis[v]+1==dis[u]&&w>0)
            {
                pre[v]=i;
                u=v,flow=min(flow,w);
                if(u==ee)
                {
                    while(u!=ss)
                    {
                        j=pre[u];
                        edge3[j].w-=flow;
                        edge3[j^1].w+=flow;
                        u=edge3[j^1].v;
                    }
                    ans+=flow,flow=N;
                }
                break;
            }
        }
        if(i==-1)
        {
            if(--gap[dis[u]]==0) break;
            cur[u]=first3[u];
            minn=n-1;
            for(j=first3[u];j!=-1;j=edge3[j].next)
            {
                v=edge3[j].v,w=edge3[j].w;
                if(w>0)
                {
                    minn=min(minn,dis[v]);
                }
            }
            dis[u]=minn+1;
            gap[dis[u]]++;
            if(u!=ss)
            {
                u=edge3[pre[u]^1].v;
            }
        }
    }
    return;
}

int main()
{
    int t,i;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&gg[i].u,&gg[i].v,&gg[i].w);
        }
        scanf("%d%d",&ss,&ee);

        memset(first1,-1,sizeof(first1));
        num=0;
        for(i=1;i<=m;i++)
        {
            addedge(gg[i].u,gg[i].v,gg[i].w,edge1,first1);
        }
        calculate(edge1,first1,dis1,ss);

        memset(first2,-1,sizeof(first2));
        num=0;
        for(i=1;i<=m;i++)
        {
            addedge(gg[i].v,gg[i].u,gg[i].w,edge2,first2);
        }
        calculate(edge2,first2,dis2,ee);

        judge();

        isap();

        printf("%d\n",ans);
    }
    return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值