[HDU 6582] Path

49 篇文章 0 订阅
22 篇文章 0 订阅

题目描述:

给你一张图,你可以堵上一条边,代价就是这条边在长度,问你如何用最小的代价使得1->n不能走最短路!

题目分析:

首先我们正反跑两次SPFA,求出那条边在最短路上,然后把这些边扔进最大流里,跑个最小鸽就好了。

题目链接:

HDU 6582

代码:

#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#define int long long
const int inf=0x7fffffff;
const int maxm=1e5+100;
int n,m;
struct node{
	int u,v,c;
}a[maxm];
namespace maxflow{
	int cnt=1;
	int head[maxm],net[maxm*2],to[maxm*2],cap[maxm*2];
	std::queue <int> dl;
	int deep[maxm];
	inline void clear()
	{
		memset(head,0,sizeof(head));
		cnt=1;
	}
	inline void addedge(int u,int v,int c)
	{
		cnt++;
		to[cnt]=v,cap[cnt]=c,net[cnt]=head[u],head[u]=cnt;
		cnt++;
		to[cnt]=u,cap[cnt]=0,net[cnt]=head[v],head[v]=cnt;
	}
	inline bool BFS(int s,int t)
    {
        memset(deep,-1,sizeof(deep));
        dl.push(s);
        deep[s]=0;
        while(!dl.empty())
        {
            int now=dl.front();
            dl.pop();
            for(int i=head[now];i;i=net[i])
            if(cap[i]&&deep[to[i]]==-1)
            deep[to[i]]=deep[now]+1,dl.push(to[i]);
        }
        return deep[t]!=-1;
    }
    int DFS(int now,int flow,int t)
    {
        if(now==t) return flow;
        int used=0,w;
        for(int i=head[now];i;i=net[i])
        if(cap[i]&&deep[to[i]]==deep[now]+1)
        {
            w=DFS(to[i],std::min(cap[i],flow-used),t);
            used+=w;
            cap[i]-=w,cap[i^1]+=w;
            if(flow==used) return used;
        }
        if(!used) deep[now]=-1;
        return used;
    } 
    inline int Dinic(int s,int t)
    {
        int ans=0;
        while(BFS(s,t)) ans+=DFS(s,inf,t);
        return ans;
    }
}
struct SPFA{
	int head[maxm],to[maxm*2],net[maxm*2],cost[maxm*2],dis[maxm];
	int cnt;
	bool vis[maxm];
	std::queue <int> dl;
	inline void clear()
	{
		memset(head,0,sizeof(head));
		memset(vis,0,sizeof(vis));
		cnt=0;
	}
	inline void addedge(int u,int v,int c)
	{
		to[++cnt]=v,cost[cnt]=c,net[cnt]=head[u],head[u]=cnt;
	}
	inline bool BFS(int s,int t)
	{
		memset(dis,127,sizeof(dis));
		dl.push(s);
		dis[s]=0,vis[s]=1;
		while(!dl.empty())
		{
			int now=dl.front();
			dl.pop();
			vis[now]=0;
			for(int i=head[now];i;i=net[i])
			if(dis[to[i]]>dis[now]+cost[i])
			{
				dis[to[i]]=dis[now]+cost[i];
				if(!vis[to[i]]) dl.push(to[i]),vis[to[i]]=1;
			}
		} 
		return dis[t]==dis[0];
	}
}spfa[2];
inline int work()
{
	maxflow::clear();
    spfa[0].clear();
    spfa[1].clear();
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int u,v,c;
		scanf("%lld%lld%lld",&u,&v,&c);
		a[i]=(node){u,v,c};
		spfa[0].addedge(u,v,c);
		spfa[1].addedge(v,u,c);
	}
	if(spfa[0].BFS(1,n)) return 0;
	spfa[1].BFS(n,1);
	int dis=spfa[0].dis[n];
	for(int i=1;i<=m;i++)
	if((spfa[0].dis[a[i].u]+spfa[1].dis[a[i].v]+a[i].c)==dis) maxflow::addedge(a[i].u,a[i].v,a[i].c);
	return maxflow::Dinic(1,n);
}
signed main()
{
	int t;
	scanf("%lld",&t);
	for(int i=1;i<=t;i++) printf("%lld\n",work());
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值