打井&口袋的天空
首先读题与自我欺骗,觉得多个井不知道怎么处理,看到联通整个牧场以为是只有一个井......
然后关于点的不知道怎么处理,于是把点与边一起排序:
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(1≤N≤1000,1≤M≤10000,1≤K≤10)
接下来MM个数每行三个数X,Y,LX,Y,L,表示XX云和YY云可以通过LL的代价连在一起。(1 \le X,Y \le N,0 \le L<10000)(1≤X,Y≤N,0≤L<10000)
30\%30%的数据N \le 100,M \le 1000N≤100,M≤1000
输出格式:
对每组数据输出一行,仅有一个整数,表示最小的代价。
如果怎么连都连不出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 }