打井&口袋的天空

首先读题与自我欺骗,觉得多个井不知道怎么处理,看到联通整个牧场以为是只有一个井......

然后关于点的不知道怎么处理,于是把点与边一起排序:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm> 
 4 using namespace std;
 5 #define debug(x) cout<<#x<<" = "<<x<<endl; 
 6 const int maxn=307;
 7 int n,minn=0x7f7f7f7f,nod;
 8 int w[maxn],map[maxn][maxn],head[maxn],num,fa[maxn];
 9 struct Edge{
10     bool node;
11     int next,from,to,dis;
12     bool vis;
13 }edge[maxn*maxn];
14 void add(int from,int to,int dis){
15     edge[++num].next=head[from];
16     edge[num].from=from;
17     edge[num].to=to;
18     edge[num].dis=dis;
19     head[from]=num;
20 }
21 bool cmp(Edge a,Edge b){
22     return a.dis<b.dis;
23 }
24 int find(int x){
25     if(fa[x]==x) return x;
26     return fa[x]=find(fa[x]);
27 }
28 void merge(int x,int y){
29     int fx=find(x);int fy=find(y);
30     if(fx!=fy) fa[fx]=fy;
31 }
32 int kruskal(){
33     for(int i=1;i<=n;i++) fa[i]=i; 
34     int ans=0;int cnt=0;
35     for(int i=1;i<=num;i++){
36         if(edge[i].node==true){
37             if(edge[i].vis==false){
38                 edge[i].vis=true;
39                 ans+=edge[i].dis;cnt++;
40             }
41         }
42         else{
43             int u=edge[i].from;int v=edge[i].to;
44             if(edge[u].vis==true&&edge[v].vis==true) continue;
45             if(edge[u].vis==true&&edge[v].vis==false){
46                 edge[v].vis=true;
47                 ans+=edge[i].dis;
48                 merge(u,v);cnt++;
49             }
50             if(edge[u].vis==false&&edge[v].vis==true){
51                 edge[u].vis=true;
52                 ans+=edge[i].dis;
53                 merge(u,v);cnt++;
54             }
55             if(edge[u].vis==false&&edge[v].vis==false){
56                 edge[u].vis=true;edge[v].vis=true;
57                 ans+=edge[i].dis;
58                 merge(u,v);cnt+=2;
59             }
60         }
61         if(cnt==n) return ans;
62     }
63 }
64 int main(){
65     cin>>n;
66     for(int i=1;i<=n;i++){
67         cin>>w[i];
68         edge[++num].node=true;
69         edge[num].dis=w[i];
70         if(w[i]<minn){
71             minn=w[i];
72             nod=num;
73         }
74     }
75     for(int i=1;i<=n;i++)
76         for(int j=1;j<=n;j++)
77             cin>>map[i][j];
78     for(int i=1;i<=n;i++)
79         for(int j=i+1;j<=n;j++)
80             if(map[i][j]!=0){
81                 add(i,j,map[i][j]);
82                 add(j,i,map[i][j]);
83             }
84     sort(edge+1,edge+num+1,cmp);
85     cout<<kruskal()+minn<<endl;
86     return 0;
87 } 

是错的,不懂

然后看了题解,就是建一个超级源点,既保证了从一个点开始计算每棵树,又保证了最小

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=307;
 6 int n,minn=0x7f7f7f7f;
 7 int val[maxn],map[maxn][maxn],head[maxn],num,fa[maxn];
 8 struct Edge{
 9     int next,from,to,dis;
10 }edge[maxn*maxn];
11 void add(int from,int to,int dis){
12     edge[++num].next=head[from];
13     edge[num].from=from;
14     edge[num].to=to;
15     edge[num].dis=dis;
16     head[from]=num;
17 }
18 bool cmp(Edge a,Edge b){
19     return a.dis<b.dis;
20 }
21 int find(int x){
22     if(fa[x]==x) return x;
23     return fa[x]=find(fa[x]);
24 }
25 void merge(int x,int y){
26     int fx=find(x);int fy=find(y);
27     if(fx!=fy) fa[fx]=fy;
28 }
29 int kruskal(){
30     for(int i=1;i<=n;i++) fa[i]=i;
31     int ans=0,cnt=0;
32     for(int i=1;i<num;i++){
33         int x=edge[i].from;int y=edge[i].to;
34         int fx=find(x);int fy=find(y);
35         if(fx!=fy) {merge(fx,fy);cnt++;ans+=edge[i].dis;}
36         if(cnt==n) return ans;
37     }
38 }
39 int main(){
40     cin>>n;
41     for(int i=1;i<=n;i++) {cin>>val[i];add(0,i,val[i]);}
42     for(int i=1;i<=n;i++)
43         for(int j=1;j<=n;j++)
44             cin>>map[i][j];
45     for(int i=1;i<=n;i++)
46         for(int j=1;j<=n;j++)
47             add(i,j,map[i][j]);
48     sort(edge+1,edge+num+1,cmp);
49     cout<<kruskal()<<endl;
50     return 0;
51 }

这种想法以前接触过不止一次

在跑SPFA的时候,邓神就说过建一个超级源点,不必枚举每个点

后来有点权,有边权的这种类似问题也做过

难受.....

口袋的天空:

题目背景

小杉坐在教室里,透过口袋一样的窗户看口袋一样的天空。

有很多云飘在那里,看起来很漂亮,小杉想摘下那样美的几朵云,做成棉花糖。

题目描述

给你云朵的个数NN,再给你MM个关系,表示哪些云朵可以连在一起。

现在小杉要把所有云朵连成KK个棉花糖,一个棉花糖最少要用掉一朵云,小杉想知道他怎么连,花费的代价最小。

输入输出格式

输入格式:

每组测试数据的

第一行有三个数N,M,K(1 le N le 1000,1 le M le 10000,1 le K le 10)N,M,K(1N1000,1M10000,1K10)

接下来MM个数每行三个数X,Y,LX,Y,L,表示XX云和YY云可以通过LL的代价连在一起。(1 le X,Y le N,0 le L<10000)(1X,YN,0L<10000)

30\%30%的数据N le 100,M le 1000N100,M1000

输出格式:

对每组数据输出一行,仅有一个整数,表示最小的代价。

如果怎么连都连不出KK个棉花糖,请输出'No Answer'。

怎样也不能建一个超级源点,题解说

n-1条边是一个生成树,n-k条边是k条生成树

所以也不用建超级源点,就直接排序,往里面加就行了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=1007;
 6 const int maxm=10007;
 7 int num,fa[maxn];
 8 int n,m,k,cnt,ans;
 9 struct Edge{
10   int from,to,dis;
11 }edge[maxm];
12 void add(int from,int to,int dis){
13   edge[++num].from=from;
14   edge[num].to=to;
15   edge[num].dis=dis;
16 }
17 bool cmp(Edge a,Edge b){
18   return a.dis<b.dis; 
19 }
20 int find(int x){
21   if(fa[x]==x) return x;
22   return fa[x]=find(fa[x]);
23 }
24 void merge(int x,int y){
25   int fx=find(x);int fy=find(y);
26   if(fx!=fy) fa[fx]=fy;
27 }
28 int main(){
29   cin>>n>>m>>k;
30   for(int i=1;i<=n;i++) fa[i]=i;
31   if(n<k){cout<<"No Answer"<<endl;return 0;}
32   for(int i=1;i<=m;i++){
33     int u,v,w;cin>>u>>v>>w;
34     add(u,v,w);
35   }
36   sort(edge+1,edge+m+1,cmp);
37   for(int i=1;i<=num;i++){
38     int u=edge[i].from;int v=edge[i].to;
39     int fu=find(u);int fv=find(v);
40     if(fu!=fv){
41       merge(fu,fv);
42       ans+=edge[i].dis;
43       cnt++;
44     }
45     if(cnt==n-k){
46       cout<<ans<<endl;
47       return 0;
48     }
49   }
50   cout<<"No Answer"<<endl;
51   return 0;
52 } 
原文地址:https://www.cnblogs.com/lcan/p/9572731.html