hdu 5294 Tricks Device 最短路+最大流

Tricks Device

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Problem Description
Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu’s at the entrance of the tomb while Dumb Zhang’s at the end of it. The tomb is made up of many chambers, the total number is N. And there are M channels connecting the chambers. Innocent Wu wants to catch up Dumb Zhang to find out the answers of some questions, however, it’s Dumb Zhang’s intention to keep Innocent Wu in the dark, to do which he has to stop Innocent Wu from getting him. Only via the original shortest ways from the entrance to the end of the tomb costs the minimum time, and that’s the only chance Innocent Wu can catch Dumb Zhang.
Unfortunately, Dumb Zhang masters the art of becoming invisible(奇门遁甲) and tricks devices of this tomb, he can cut off the connections between chambers by using them. Dumb Zhang wanders how many channels at least he has to cut to stop Innocent Wu. And Innocent Wu wants to know after how many channels at most Dumb Zhang cut off Innocent Wu still has the chance to catch Dumb Zhang.
 

Input
There are multiple test cases. Please process till EOF.
For each case,the first line must includes two integers, N(<=2000), M(<=60000). N is the total number of the chambers, M is the total number of the channels.
In the following M lines, every line must includes three numbers, and use ai、bi、li as channel i connecting chamber ai and bi(1<=ai,bi<=n), it costs li(0<li<=100) minute to pass channel i.
The entrance of the tomb is at the chamber one, the end of tomb is at the chamber N.
 

Output
Output two numbers to stand for the answers of Dumb Zhang and Innocent Wu’s questions.
 

Sample Input
  
  
8 9 1 2 2 2 3 2 2 4 1 3 5 3 4 5 4 5 8 1 1 6 2 6 7 5 7 8 1
 

Sample Output
  
  
2 6
 

题意:

给一个图,起点1,终点n

必须走最短路才能从起点到终点。问至少删除几条边使得无法从起点到终点。

且删除最多几条边,还可以从起点到终点。(可以有多条最短路)

分析:

链式前向星存储边,SPFA做最短路,用Road[]数组来维护最短路边的条数,所有满足dist[u] = dist[v] + w(v,u)的边都是最短路的边,

对这样的边,重新建图。新图加入e(u,v),边的权值为1.

对新图从 起点到重点跑一边最大流。

看似挺简单的一道题,满满的都是累。。。

代码:

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <math.h>
#include <string>
#include <vector>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <functional>
#define mem(a) memset(a,0,sizeof(a));
#define mem_1(a) memset(a,-1,sizeof(a));
#define sf(a) scanf("%d",&a)
#define sff(a,b) scanf("%d%d",&a,&b)
#define sfff(a,b,c) scanf("%d%d%d",&a,&b,&c)
const int INF = 0x3f3f3f3f;
const int MAXM = 300000;
const int MAXN = 2222;
using namespace std;
struct node
{
    int from,to,next,cost;
} ed[MAXM];
struct Edge
{
    int to,cap,next,flow;
} edge[MAXM];
int tol,head[MAXN];
/*******  初始化  ***********/
void init()
{
    tol = 0;
    mem_1(head);
}
/*******  原图加边  ***********/
void add_ed(int from,int to,int cost)
{
    ed[tol].from = from;
    ed[tol].to = to;
    ed[tol].cost = cost;
    ed[tol].next = head[from];
    head[from] = tol++;
    ed[tol].from = to;
    ed[tol].to = from;
    ed[tol].cost = cost;
    ed[tol].next = head[to];
    head[to] = tol++;

}
/*******  新图加边  ***********/
void addedge(int from,int to,int cap)
{
    edge[tol].to = to;
    edge[tol].cap = cap;
    edge[tol].flow = 0;
    edge[tol].next = head[from];
    head[from] = tol++;
    edge[tol].to = from;
    edge[tol].cap = 0;
    edge[tol].flow = 0;
    edge[tol].next = head[to];
    head[to] = tol++;
}
/*******  SPFA 求最短路***********/
bool vis[MAXN];
int dist[MAXN];
int road[MAXN];  //记录最短的条数
void SPFA(int start)
{
    memset(vis,0,sizeof(vis));
    memset(dist,INF,sizeof(dist));
    memset(road,INF,sizeof(road));
    dist[start] = 0;
    road[start] = 0;
    vis[start] = 1;
    queue<int> Q;
    Q.push(start);
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        for(int i = head[u]; ~i; i = ed[i].next)
        {
            int v = ed[i].to;
            if(dist[v]>dist[u]+ed[i].cost)
            {
                dist[v] = dist[u] + ed[i].cost;
                road[v] = road[u] + 1;
                if(!vis[v])
                {
                    vis[v] = 1;
                    Q.push(v);
                }
            }
            else if(dist[v]==dist[u] + ed[i].cost)
            {
                if(road[v] > road[u] + 1)
                {
                    road[v] = road[u] + 1;
                    if(!vis[v])
                    {
                        vis[v] = 1;
                        Q.push(v);
                    }
                }
            }
        }
    }
}
/**********  sap模板    求最大流 *********/
int pre[MAXN];
int gap[MAXN],dep[MAXN],cur[MAXN];
int sap(int start , int end ,int N)
{
    mem(gap);
    mem(dep);
    memcpy(cur,head,sizeof(head));
    int u = start;
    pre[u] = -1;
    gap[0] = N;
    int ans = 0;
    while(dep[start]< N)
    {
        if(u==end)
        {
            int Min = INF;
            for(int i= pre[u]; i!=-1; i=pre[edge[i^1].to])
            {
                if(Min > edge[i].cap - edge[i].flow)
                    Min = edge[i].cap - edge[i].flow;
            }
            for(int i= pre[u]; i!=-1; i=pre[edge[i^1].to])
            {
                edge[i].flow += Min;
                edge[i^1].flow -= Min;
            }
            u = start;
            ans+=Min;
            continue;
        }
        bool flag = false;
        int v;
        for(int i=cur[u]; i!=-1; i = edge[i].next)
        {
            v = edge[i].to;
            if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u])
            {
                flag = true;
                cur[u] = pre[v] = i;
                break;
            }
        }
        if(flag)
        {
            u = v;
            continue;
        }
        int Min = N;
        for(int  i=head[u]; i!=-1; i = edge[i].next)
        {
            if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
            {
                Min = dep[edge[i].to];
                cur[u] = i;
            }
        }
        gap[dep[u]]--;
        if(!gap[dep[u]])
            return ans;
        dep[u] = Min+1;
        gap[dep[u]]++;
        if(u!=start) u = edge[pre[u]^1].to;
    }
    return ans;
}

int main()
{
    int n,m;
    int x,y,z;
    while(sff(n,m)!=EOF)
    {
        init();
        for(int i=1; i<=m; i++)
        {
            sfff(x,y,z);
            if(x==y) continue;
            add_ed(x-1,y-1,z);  //定点从零点起
        }
        SPFA(0);


        int allNum = tol;
        init();
        int u,v;
        for(int i=0; i<allNum; i++)   //伟大的建新图的过程
        {
            u = ed[i].from;
            v = ed[i].to;
            if(dist[v] == dist[u]+ed[i].cost)
                addedge(u,v,1);
        }
        int ans1 = sap(0,n-1,n);     //最大流跑起来
        int ans2 = m - road[n-1];
        printf("%d %d\n",ans1,ans2);
    }
    return 0;
}





  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值