zoukankan      html  css  js  c++  java
  • 打井&口袋的天空

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

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

     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 } 
  • 相关阅读:
    Oracle 冷备份详解【实战案例】
    Oracle Procedure记录
    【基础操作】1.表操作
    Oracle的基本语法,存储函数及触发器
    有志者事竟成 — 雷林鹏
    Les13 性能管理
    SharePoint 2010 创建联系人列表和使用联系人列表
    在SharePoint 2010中创建联系人Web数据库网站
    C#中数组如何赋值
    What Can Happen When You Try to Convert a Standard SharePoint 2010 Farm to Enterprise
  • 原文地址:https://www.cnblogs.com/lcan/p/9572731.html
Copyright © 2011-2022 走看看