CodeForces 125E MST Company

 

E. MST Company
time limit per test  8 seconds
memory limit per test  256 megabytes
input  standard input
output  standard output

The MST (Meaningless State Team) company won another tender for an important state reform in Berland.

There are n cities in Berland, some pairs of the cities are connected by roads. Each road has its price. One can move along any road in any direction. The MST team should carry out the repair works on some set of roads such that one can get from any city to any other one moving only along the repaired roads. Moreover, this set should contain exactly k capital roads (that is, the roads that start or finish in the capital). The number of the capital is 1.

As the budget has already been approved, the MST Company will profit by finding the set with minimum lengths of roads.

Input

The first input line contains three integers n, m, k (1 ≤ n ≤ 5000;0 ≤ m ≤ 105;0 ≤ k < 5000), where n is the number of cities in the country, m is the number of roads in the country, k is the number of capital roads in the required set. Then m lines enumerate the roads in question. Each road is specified by three numbers ai, bi, wi (1 ≤ ai, bi ≤ n1 ≤ w ≤ 105), where ai, bi are the numbers of cities linked by a road and wi is its length.

Between each pair of cities no more than one road exists. There are no roads that start and finish in one city. The capital's number is 1.

Output

In the first line print the number of roads in the required set. The second line should contain the numbers of roads included in the sought set. If the sought set does not exist, print -1.

Examples
input
4 5 2
1 2 1
2 3 1
3 4 1
1 3 3
1 4 2
output
3
1 5 2

 

代码基本靠抄,自己吃枣药丸。

 

传说这题做法主要有两种:

一:

  先做出不含1点的最小生成树。

  如果将连接到1的边加进生成树会形成环的话,就在环中找到最长的一条边删掉。

  ↑计算加某条边会使答案增加的量,然后从连接到1的边里选出增量最小的边进行上述操作,重复k次得到最终结果。

  ↑写了好久好久都写不出,怒砸键盘,换第二种写法。结果第二天看到隔壁yhx大神分分钟按上述算法切题……

  害怕。

  附传送门:http://blog.csdn.net/sdfzyhx/article/details/53500851

 

  还有自己写了半天调不对的代码,姑且先存着:

  

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<queue>
  6 #define LL unsigned long long
  7 using namespace std;
  8 const int mxn=5010;
  9 int read(){
 10     int x=0,f=1;char ch=getchar();
 11     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 12     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 13     return x*f;
 14 }
 15 struct edge{int x,y;int v;int id;}e[mxn*10];
 16 int cmp(const edge a,const edge b){return a.v<b.v;}
 17 struct sdd{int v,nxt,dis,id;}eg[mxn<<2];
 18 int hd[mxn],egct=0;
 19 void add_edge(int u,int v,int dis,int id){
 20     eg[++egct].v=v;eg[egct].nxt=hd[u];eg[egct].dis=dis;eg[egct].id=id;hd[u]=egct;return;
 21 }
 22 int n,m,k;
 23 int ans=0;
 24 int st[mxn],top;
 25 int fir[mxn*10],mct=0;//存所有与1相连的边 
 26 //
 27 int fa[mxn];
 28 int find(int x){if(fa[x]==x)return x;return fa[x]=find(fa[x]);}
 29 int add[mxn];
 30 bool del[mxn];
 31 bool intree[mxn];
 32 inline void init(int x){for(register int i=1;i<=x;i++)fa[i]=i;}//并查集初始化 
 33 void PD(){
 34     int cnt=0;
 35     for(int i=2;i<=n;i++){if(find(i)==i)cnt++;}
 36     if(cnt>k){printf("-1\n");exit(0);}//联通块数多于可加边数,无解 
 37     return;
 38 }
 39 int mx[mxn],m_id[mxn];
 40 void DFS(int u,int f){
 41     for(int i=hd[u];i;i=eg[i].nxt){
 42         int v=eg[i].v;
 43         if(v==f || !intree[eg[i].id])continue;
 44         if(u==1){mx[v]=1e9;m_id[v]=0;}
 45         bool flag=0;
 46         if(eg[i].dis<mx[v]){
 47             mx[v]=eg[i].dis;
 48             m_id[v]=eg[i].id;
 49             flag=1;
 50         }
 51         if(mx[v]>mx[u]){
 52             mx[v]=mx[u];
 53             m_id[v]=m_id[u];
 54             flag=1;
 55         }
 56         if(flag)DFS(v,u);
 57     }
 58     return;
 59 }
 60 int belone[mxn];
 61 void solve(){
 62     top=0;
 63     int i,j,u,v;
 64     int cnt=0;
 65     //
 66     sort(e+1,e+m+1,cmp);
 67     init(n);
 68     for(i=1;i<=m;i++){
 69         if(e[i].x==1 || e[i].y==1)continue;
 70         u=find(e[i].x);v=find(e[i].y);
 71         if(u!=v){
 72             fa[u]=v;
 73             ans+=e[i].v;
 74             intree[e[i].id]=1;//记录是否在树中
 75             add_edge(e[i].x,e[i].y,e[i].v,e[i].id);
 76             add_edge(e[i].y,e[i].x,e[i].v,e[i].id);
 77             cnt++;
 78         }
 79         if(cnt==n-2)break;//除1以外都连通时,退出 
 80     }
 81     //kruskal处理出除点1以外的生成树 
 82     PD();
 83     //
 84     init(n);
 85     for(i=2;i<=n;i++){belone[i]=find(i);}
 86     for(i=1;i<=m;i++)//找出待加的1边 
 87         if(e[i].x==1 || e[i].y==1){
 88             if(e[i].y==1)swap(e[i].x,e[i].y);
 89             fir[++mct]=i;
 90         }
 91     memset(mx,0x3f,sizeof mx);
 92     for(i=1;i<=mct;i++){
 93         if(e[fir[i]].v<mx[belone[e[fir[i]].y]]){
 94             mx[belone[e[fir[i]].y]]=e[fir[i]].v;
 95             m_id[belone[i]]=fir[i];
 96         }
 97     }
 98     cnt=0;
 99     for(i=1;i<=n;i++){//加入和点1相连的边使图连通 
100         if(belone[i]!=i)continue;
101         intree[e[m_id[i]].id]=1;
102         cnt++;
103         ans+=e[m_id[i]].v;
104         add_edge(e[m_id[i]].x,e[m_id[i]].y,e[m_id[i]].v,e[m_id[i]].id);
105         add_edge(e[m_id[i]].y,e[m_id[i]].x,e[m_id[i]].v,e[m_id[i]].id);
106     }
107     for(i=cnt+1;i<=k;i++){
108         DFS(1,0);
109         int tmp1=1e9,tmp2,tmp3;
110         for(j=1;j<=mct;j++){//尝试替换1边 
111             int to=e[fir[j]].y;
112             if(e[fir[j]].v-mx[to]<tmp1){
113                 tmp1=e[fir[j]].v+mx[to];
114                 tmp2=fir[j];
115                 tmp3=m_id[to];
116             }
117             ans+=tmp1;
118             intree[e[tmp2].id]=1;//加入1边 
119             intree[e[tmp3].id]=0;//删除一条边 
120         }
121     }
122     return;
123 }
124 int main()
125 {
126     int i,j;
127     n=read();m=read();k=read();
128     for(i=1;i<=m;i++){
129         e[i].x=read();e[i].y=read();
130         e[i].v=read();e[i].id=i;
131         fa[find(e[i].x)]=fa[find(e[i].y)];
132     }
133     for(i=1;i<n;i++)if(find(i)!=find(i+1)){
134         printf("-1\n");return 0;
135     }//无法连通,无解 
136     solve();
137     printf("%d\n",ans);
138     return 0;
139 }
View Code

 

二:

  加边的增量具有单调性。二分可能的增量,以此为基准将与1相连的边排序并加入生成树,看何时能正好加入k条,就是答案了。

  

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<queue>
 6 #define LL unsigned long long
 7 using namespace std;
 8 const double eps=1e-5;
 9 const int mxn=5010;
10 int read(){
11     int x=0,f=1;char ch=getchar();
12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 struct edge{
17     int x,y;
18     int v;
19     int id;
20 }e[mxn*20];
21 double mid;
22 int cmp(const edge a,const edge b){
23     return (double)(a.x==1)*mid+(double)a.v < (double)(b.x==1)*mid+(double)b.v;
24 }
25 int n,m,k;
26 int tot=0;
27 //
28 int fa[mxn];
29 int find(int x){
30     if(fa[x]==x)return fa[x];
31     return fa[x]=find(fa[x]);
32 }
33 int ans[mxn],mct=0;
34 void solve(bool flag){
35     for(int i=1;i<=n;i++)fa[i]=i;
36     sort(e+1,e+m+1,cmp);
37     tot=0;mct=0;
38     for(int i=1;i<=m;i++){
39         int u=find(e[i].x),v=find(e[i].y);
40         if(u!=v && (tot+(e[i].x==1)<=k || flag)){
41             fa[u]=v;
42             ans[++mct]=e[i].id;
43             if(e[i].x==1)tot++;
44         }
45     }
46 }
47 int main()
48 {
49     n=read();m=read();k=read();
50     int i,j;
51     int dg1=0;
52     for(i=1;i<=m;i++){
53         e[i].x=read();e[i].y=read();e[i].v=read();e[i].id=i;
54         if(e[i].x>e[i].y)swap(e[i].x,e[i].y);
55         if(e[i].x==1)dg1++;
56     }
57     if(dg1<k || (n>1 && k==0)){printf("-1\n");return 0;}//不能满足k要求 
58     mid=0;
59     solve(1);
60     if(mct<n-1){printf("-1\n");return 0;}//不能生成树
61     double l=-1e5,r=1e5;
62     while(l+eps<r && tot!=k){
63         mid=(l+r)/2;
64         solve(1);
65         if(tot<k)r=mid;
66         else l=mid;
67     }
68     if(tot!=k)mid=(l+r)/2;
69     solve(0);
70     printf("%d\n",mct);
71     for(i=1;i<=mct;i++)printf("%d ",ans[i]);
72     return 0;
73 }

 

转载于:https://www.cnblogs.com/SilverNebula/p/6142719.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值