多校 hdu 5294 Tricks Device 最短路+最大流

Tricks Device

題意是要找最少斷有幾條路能使無邪抓不到寧,最多斷幾條路還能抓到,首先是求最短路中最小步數cnt,用(總路數-cnt)即最多的,然後再在所有最短路的基礎上找邊權爲1的最大流,原因就是到達終點的最短路即使不同,但也有可能經過同一條路到達終點,而最大流則可以求出最短路中終點的最大入度。

#include <bits/stdc++.h>
using namespace std;
const int M=60005;
const int N=20005;
const int INF=0x7fffffff;
struct edge{
   int to,cost;
   int rev;
}e[N];
vector<edge>mp[N];
vector<pair<int,int> >G[N];
int n,m;
int dist[M];
int used[M];
int cnt[M];
int nod[M];
int level[M];
int iter[M];
bool vis[M];
queue<int>q;
void spfa(int s,int t){          //spfa算法最短路
    memset(used,0,sizeof used); 
    memset(dist,127,sizeof dist);
    memset(cnt,127,sizeof cnt);
   dist[s]=0;
   used[s]=1;
   cnt[s]=0;
   while(!q.empty()) q.pop();
   q.push(s);
   while(!q.empty()){
      int v=q.front();
      q.pop();
      used[v]=0;
      for(int i=0;i<G[v].size();i++){
          int u=G[v][i].first;
          int c=G[v][i].second;
          if(dist[u]==dist[v]+c) //計算最小步數   
           cnt[u]=min(cnt[v]+1,cnt[u]);   
          if(dist[u]>dist[v]+c){
             dist[u]=dist[v]+c;
             cnt[u]=cnt[v]+1;
            if(!used[u]){ //由於會有重邊
             used[u]=1;
             q.push(u);
             }
          }
      }
   }
}

bool bfs(){         //最大流中求最短增廣路
   int s=1,t=n;
   queue<int>qq;
   memset(vis,false,sizeof vis);
   memset(level,-1,sizeof level);
   level[s]=0;
   vis[s]=true;
   qq.push(s);
   while(!qq.empty()){
       int u =qq.front();
       qq.pop();
       vis[u]=false;
       for(int i=0;i<mp[u].size();i++){
           edge &ee=mp[u][i];
           if(ee.cost>0 && level[ee.to]<0&&!vis[ee.to]){
               vis[ee.to]=true;
              level[ee.to]=level[u]+1;
              if(ee.to==t) return true;
              qq.push(ee.to);
           }
       }
   }
   return false;
}
void add(int u,int v){   //添加最短路重新構成圖
    mp[u].push_back((edge){v,1,mp[v].size()});
    mp[v].push_back((edge){u,0,mp[u].size()-1});
}
void build()  //建圖
{
    for(int i= 1;i<=n;i++)
    mp[i].clear();
    for(int i=1;i<=n;i++){
        for(int j=0;j<G[i].size();j++){
          int u=G[i][j].first;
          int c=G[i][j].second;
          if(dist[u]==dist[i]+c){
              add(i,u);
          }
        }
    }
     /*for(int i=1;i<=n;i++){
       for(int j=0;j<mp[i].size();j++)
           cout<<i<<" "<<mp[i][j].to<<" "<<mp[i][j].cost<<" "<<mp[i][j].rev<<endl;
    }*/
}

int dfs(int v,int t,int f){  //求一條增廣路上的最大流
   if(v==t||f==0) return f;
   for(int i=0;i <mp[v].size();i++){
        edge &ee=mp[v][i];
        if(ee.cost>0 && level[ee.to]>level[v]){
            int d=dfs(ee.to,t,min(f,ee.cost));
            if(d>0){
               ee.cost-=d;
               mp[ee.to][ee.rev].cost+=d;
               return d;
            }
        }
   }
   return 0;
}
int max_flow(){   //dinic算法求最大流
    int flow=0;
    memset(vis,false,sizeof vis);
   // memset(iter,0,sizeof iter);
    while(bfs()){    //還有增廣路
         if(level[n]<0) break;
     //    memset(iter,0,sizeof iter);
        int f=dfs(1,n,INF);
        flow+=f;  //總的流
    }
    return flow;
}
int main()
{
   while(scanf("%d%d",&n,&m)!=-1){
       for(int i=1;i<=n;i++)
          G[i].clear();
      memset(cnt,0,sizeof cnt); 
       for(int i=0;i<m;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            G[x].push_back(make_pair(y,z));
            G[y].push_back(make_pair(x,z));
        }
        spfa(1,n);
        build();
        int ans=max_flow();
        cout<<ans<<" ";
        cout<<m-cnt[n]<<endl;
   }
   return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章