POJ3921/HDU2485 Destroying the bus stations

 题目大意是给你一个图,每条边权值为1,你在其中毁坏多少个点可以使得从1到n至少要花费k+1的时间
显然意思就是要求对于一条边(u,v)dist[1][u]+dist[v][n]+1<=k,那么如果当前1->u的最短路径都大于k则说明这条路径上的点u、v可以暂时不予考虑
我们只考虑 dist[1][u]+dist[v][n]+1<=k的情况(dist为多元最短路径),那么根据dist重新构图,满足dist[1][u]+dist[v][n]+1<=k的点(u,v)就加入图中,
根据题意就是要保证这个图不能联通,那么求出这个图的点连通度就是答案了,注意这个图是有向图
 
#include <iostream>
#include <string.h>
using namespace std;
const int MAXN = 101;
const int MAXE = 5000;
struct node
{
       int v, w, next;       
}mapp[MAXE];
int id;
int head[MAXN];
int tempmap[MAXN][MAXN];
void init()
{
     id = 0;
     memset(head, -1, sizeof(head));     
}
void addedge(int u, int v, int val)
{
     mapp[id].v = v, mapp[id].w = val, mapp[id].next = head[u], head[u] = id ++;
     
     mapp[id].v = u, mapp[id].w = 0, mapp[id].next = head[v], head[v] = id ++;
}
const int inf = 1<<29;
int cur[MAXN], dist[MAXN], pre[MAXN], gap[MAXN];
int SAP(int s, int e, int n)
{
    memcpy(cur, head, sizeof(head));
    memset(dist, 0, sizeof(dist));
    memset(gap, 0, sizeof(gap));
    int u, v;
    int flow = 0;
    int bottle = inf;
    gap[s] = n;
    u = pre[s] = s;
    bool flag = true;
    while (dist[s] < n){
          flag = false;
          for (int &j = cur[u]; j != -1; j = mapp[j].next){
              v = mapp[j].v;
              if (mapp[j].w > 0 && dist[v]+1 == dist[u]){
                 flag = true;
                 if (mapp[j].w < bottle){
                    bottle = mapp[j].w;              
                 }
                 pre[v] = u;
                 u = v;
                 if (u == e){
                    flow += bottle;
                    while (u != s){
                          u = pre[u];
                          mapp[cur[u]].w -= bottle;
                          mapp[cur[u]^1].w += bottle;
                    }
                    bottle = inf;      
                 }        
                 break; 
              }         
          }
          if (flag) continue;
          int mindis = n;
          for (int j = head[u]; j != -1; j = mapp[j].next){
              v = mapp[j].v;
              if (mapp[j].w > 0 && mindis > dist[v]){
                 mindis = dist[v], cur[u] = j;              
              }    
          } 
          if (!(--gap[dist[u]])){
             break;                       
          }
          gap[dist[u] = mindis+1] ++;
          u = pre[u];
    }
    return flow;
}

int n;
void floyd()
{
     for (int k = 1; k <= n; k ++){
         for (int i = 1; i <= n; i ++){
             for (int j = 1; j <= n; j ++){
                 if (tempmap[i][j] > tempmap[i][k]+tempmap[k][j] && i != j){
                    tempmap[i][j] = tempmap[i][k]+tempmap[k][j];
                 }    
             }
         }    
     }     
}
int a[MAXE], b[MAXE];
int main()
{
    int m, k;
    while (scanf("%d%d%d", &n, &m, &k) && (n+m+k)){
          init();
          for (int i = 1; i <= n; i ++){
              for (int j = 1; j <= n; j ++)tempmap[i][j] = inf;    
              tempmap[i][i] = 0;
          }
          for (int i = 0; i < m; i ++){
              int a1, b1;
              scanf("%d%d", &a1, &b1);
              tempmap[a1][b1] = 1;
          }
          int kao = 0;
          for (int i = 1; i <= n; i ++){
              for (int j = 1; j <= n; j ++){
                  if (tempmap[i][j] == 1){
                     a[kao] = i;
                     b[kao ++] = j;                   
                  }    
              }
          }
          floyd();
          for (int i = 0; i < kao; i ++){
              if (tempmap[1][a[i]]+tempmap[b[i]][n] < k){
                    addedge(a[i]+n, b[i], inf);
              }
          }
          for (int i = 1; i <= n; i ++)addedge(i, i+n, 1);   
          int ans = SAP(n+1, n, 2*n);
            
          if (ans == inf)printf("%d\n", n);
          else
              printf("%d\n", ans);
    }    
    return 0;    
} 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值