Codeforces 240E. Road Repairs 最小树形图+输出路径

题目大意:

 有N个城市,城市1是首都 ,有M条路,路的状态有两种,

一种是可行的,另一种是不可行的,不可行的可以修成可行,

但要花1单位的费用 现在问,要让首都能到任意城市,需要

花费的最小代价是多少,需要修的路是哪几条

解题思路:

最小树形图+输出路径(当成模板)

题解代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=2001000;
int n,m;//******
struct Edge {
   int u,v,cost,id,ru,rv,rcost;
} edge[maxn];
void add_Edge(int id,int u,int v,int c) {
   edge[id].id=id;
   edge[id].u=edge[id].ru=u;
   edge[id].v=edge[id].rv=v;
   edge[id].cost=edge[id].rcost=c;
}
int pre[maxn],id[maxn],vis[maxn],in[maxn];
 /*!!!!
int preid[maxn],useE[maxn];
int eA[maxn],eD[maxn];
int ex;//  */
int zhuliu(int root,int n,int m,Edge edge[]) {
   int ex=m,res=0;
   while(true) {
      for(int i=0; i<n; i++) in[i]=INF;
      for(int i=0; i<m; i++) {
         if(edge[i].u!=edge[i].v&&edge[i].cost<in[edge[i].v]) {
            pre[edge[i].v]=edge[i].u;
            in[edge[i].v]=edge[i].cost;
            preid[edge[i].v]=edge[i].id; !!!!
         }
      }
      for(int i=0; i<n; i++)
         if(i!=root&&in[i]==INF) return -1;
      int tn=0;
      memset(id,-1,sizeof(id));
      memset(vis,-1,sizeof(vis));
      in[root]=0;
      for(int i=0; i<n; i++) {
         res+=in[i];
         int v=i;
          /*!!!!
         if(i!=root) useE[preid[i]]++;
         while(vis[v]!=i&&id[v]==-1&&v!=root) {
            vis[v]=i;
            v=pre[v];
         }
         if(v!=root&&id[v]==-1) {
            for(int u=pre[v]; u!=v; u=pre[u]) id[u]=tn;
            id[v]=tn++;
         }//   */
      }
      if(tn==0) break;
      for(int i=0; i<n; i++)
         if(id[i]==-1) id[i]=tn++;
      for(int i=0; i<m; i++) {
         int v=edge[i].v;
         edge[i].u=id[edge[i].u];
         edge[i].v=id[edge[i].v];
         if(edge[i].u!=edge[i].v) {
            edge[i].cost-=in[v];
             !!!! /*
            eA[ex]=edge[i].id;
            eD[ex]=preid[v];
            edge[i].id=ex;
            ex++;//  */
         }
      }
      n=tn;
      root=id[root];
   }
    !!!!  /*
   for(int i=ex-1; i>=m; i--) {
      if(useE[i]) {
         useE[eA[i]]++;
         useE[eD[i]]--;
      }
   }//    */
   return res;
}

int main() {
   freopen("input.txt","r",stdin);
   freopen("output.txt","w",stdout);
   scanf("%d%d",&n,&m);
   for(int i=0,a,b,c; i<m; i++) {
      scanf("%d%d%d",&a,&b,&c);
      a--;
      b--;
      add_Edge(i,a,b,c);
   }
   int lens = zhuliu(0,n,m,edge);
   if(lens==0||lens==-1) {
      printf("%d\n",lens);
      return 0;
   }
   printf("%d\n",lens);
   for(int i=0; i<m; i++) {
      if(useE[i]&&edge[i].rcost)
         printf("%d ",i+1);
   }
   putchar(10);
   return 0;
}

THE END;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值