【HDU 5889】【最短路+最小割 裸题】Barricade 【n点m边无向图在最短路上设置障碍,使得不管怎么走都会碰到障碍】

传送门:HDU 5889 Barricade

描述:

Barricade

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 841    Accepted Submission(s): 255


Problem Description
The empire is under attack again. The general of empire is planning to defend his castle. The land can be seen as  N  towns and  M  roads, and each road has the same length and connects two towns. The town numbered  1  is where general's castle is located, and the town numbered  N  is where the enemies are staying. The general supposes that the enemies would choose a shortest path. He knows his army is not ready to fight and he needs more time. Consequently he decides to put some barricades on some roads to slow down his enemies. Now, he asks you to find a way to set these barricades to make sure the enemies would meet at least one of them. Moreover, the barricade on the  i -th road requires  wi  units of wood. Because of lacking resources, you need to use as less wood as possible.
 

Input
The first line of input contains an integer  t , then  t  test cases follow.
For each test case, in the first line there are two integers  N(N1000)  and  M(M10000) .
The  i -the line of the next  M  lines describes the  i -th edge with three integers  u,v  and  w  where  0w1000  denoting an edge between  u  and  v  of barricade cost  w .
 

Output
For each test cases, output the minimum wood cost.
 

Sample Input
  
  
1 4 4 1 2 1 2 4 2 3 1 3 4 3 4
 

Sample Output
  
  
4
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   5899  5897  5896  5894  5893 
 

题意:
n点m边无向图,1为己方 n为敌方
每条边有建阻碍的花费 距离都是1

已知敌方会选择最短路来己方。要选择一些路设障碍,让敌方至少碰到一个障碍。

思路:

先跑一个最短路。

对于每一条边u-v,如果dis[v]==dis[u]+1

这条路就可能在最短路中。

然后跑个最小割(其实是最大流)

为什么酱紫保证正确呢?刚开始我也有怀疑是水数据。。

后来想了想如果不是最短路中的边,肯定无法跑到终点,至少会有一处断开。所以大胆跑最小割就行了

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
using  namespace std;

/*vector建图
  点很多的话效率会比较低
*/
const int inf=0x3f3f3f3f;
const int maxn=1005;
const int maxm=10005;//边数的最大值
vector<pair<int,int> >E[maxn];//邻接表
int n,m;
int  dis[maxn],inq[maxn];

void  init(){
    for(int i=0; i<maxn; i++)E[i].clear();
    for(int i=0; i<maxn; i++)inq[i]=0;
    for(int i=0; i<maxn; i++)dis[i]=inf;
}

void dijkstra(int s,int t){
  priority_queue<pair<int,int> >q;
  dis[s]=0;
  q.push(make_pair(-dis[s],s));//优队返回的是最大值,取负就返回的最小值
  while(!q.empty()){
    int now=q.top().second;
    q.pop();inq[now]=0;
    for(int i=0; i<E[now].size(); i++){
      int  v=E[now][i].first;
      if(dis[v]>dis[now]+E[now][i].second){
        dis[v]=dis[now]+E[now][i].second;
        q.push(make_pair(-dis[v],v));
      }
    }
  }
}


//最大流求最小割
/*ISAP+bfs初始化+栈优化
*/
struct Edge {
  int to,next,cap,flow;
}edge[maxm];//注意是maxm
int tol;
int head[maxn];
int cur[maxn],d[maxn];// 当前弧下标   结点到汇点距离下界
int p[maxn],gap[maxn];//可增广路上的上一条弧   gap优化  //比dinic多的两个数组

void init1(){
  tol=0;
  memset(head, -1, sizeof(head));
}

void addedge(int u,int v,int w,int rw = 0){
  edge[tol].to=v; edge[tol].cap=w; edge[tol].flow=0;
  edge[tol].next=head[u]; head[u]=tol++;
  edge[tol].to=u; edge[tol].cap=rw; edge[tol].flow=0;
  edge[tol].next=head[v]; head[v]=tol++;
}

int Q[maxn];
void bfs(int s,int t){//逆向进行bfs
  memset(d, -1, sizeof(d));
  memset(gap, 0, sizeof(gap));
  gap[0]=1;
  int front=0, rear=0;
  d[t]=0;
  Q[rear++]=t;
  while(front!=rear){
  int u=Q[front++];
    for(int i=head[u]; i!=-1; i=edge[i].next){
      int v=edge[i].to;
      if(d[v]!=-1)continue;
      Q[rear++]=v;
      d[v]=d[u]+1;
      gap[d[v]]++;
    }
  }
}

int S[maxn];
//输入参数:起点、终点、点的总数
//点的编号没有影响,只要输入点的总数
int sap(int s,int t,int N){
  bfs(s, t);
  memcpy(cur, head, sizeof(head));
  int top=0;
  int u=s;
  int ans=0;
  while(d[s]<N){
    if(u==t){
      int Min=inf;
      int inser;
      for(int i=0; i<top; i++)//找最小残量值
        if(Min>edge[S[i]].cap-edge[S[i]].flow){
          Min=edge[S[i]].cap-edge[S[i]].flow;
          inser=i;
        }
      for(int i=0; i<top; i++){//增广
        edge[S[i]].flow+=Min;
        edge[S[i]^1].flow-=Min;
      }
      ans+=Min;
      top=inser;
      u=edge[S[top]^1].to;
      continue;
    }
    bool ok=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 && d[v]+1==d[u]){Advance前进
        ok=true;
        cur[u]=i;
        break;
      }
    }
    if(ok){
      S[top++]=cur[u];
      u=v;
      continue;
    }
    //Retreat走不动了,撤退
    int Min=N;
    for(int i=head[u]; i!=-1; i=edge[i].next)
      if(edge[i].cap-edge[i].flow && d[edge[i].to]<Min){
        Min=d[edge[i].to];
        cur[u]=i;
      }
    gap[d[u]]--;
    if(!gap[d[u]])return ans;
    d[u]=Min+1;
    gap[d[u]]++;
    if(u!=s)u=edge[S[--top]^1].to;//退一步,沿父边返回
  }
  return ans;
}

vector<int>val[maxn];

int main(){
  int t;
  scanf("%d",&t);
  while(t--){
    scanf("%d%d",&n,&m);
    for(int i=0; i<=n; i++)val[i].clear();
    init();
    for(int i=1; i<=m; i++){
      int u,v,w;
      scanf("%d%d%d",&u,&v,&w);
      E[u].push_back(make_pair(v, 1));
      E[v].push_back(make_pair(u, 1));
      val[u].push_back(w);
      val[v].push_back(w);
    }
    dijkstra(1, n);
    init1();
    for(int u=1; u<=n; u++){
      for(int i=0; i<E[u].size(); i++){
        int v=E[u][i].first,w=val[u][i];
        if(dis[v]==dis[u]+1){
          addedge(u, v, w);
        }
      }
    }
    printf("%d\n", sap(1, n, n));
  }
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值