并查集-boj468 & boj474 送快递问题

题目描述

Mays王国的女王大人每天过着自由自在的生活,她最大的乐趣就是给邻国的帅气王子写信。但是最近,Mays王国的叔叔们变得很无聊,他们知道女王大人每次都把信委托给皇家小妹妹快递公司的小妹妹们,于是叔叔们给每一条路都设立了路障,只有小妹妹们给他们表演节目才会让小妹妹们过去。
在每一个路障,都有不同数量的叔叔,只有表演的小妹妹的数量不少与叔叔的数量的时候叔叔才会放她们过去。
为了节省开销,小妹妹快递公司希望派最少的小妹妹把女王大人的信件送到。请你告诉他们需要派几个小妹妹。

输入格式

输入第一行为数据组数T(T<=10),接下来T组数据,每组第一行为n,m,,2<=n<=10000,1<=m<=100000,表示Mays王国的道路由n个节点组成,接下来m行,每行一组u,v,c表示连接节点u,v的一条无向道路,且路障上有c个叔叔,1<=u,v<=n,0<=c<=100。女王大人和皇家小妹妹快递公司都在节点1,帅气的邻国王子住在节点n。

输出格式

每组数据输出一个数字,表示小妹妹快递公司最少需要派出的小妹妹数量。如果无论派出多少小妹妹都无法把信送到帅气的邻国王子手里,输出"shimatta!"。

输入样例

1
3 3
1 2 1
2 3 1
1 3 3

输出样例

1

   这道题我是这么做的:

既然只有100中叔叔个数的可能,那么就把所有路线上怪叔叔个数为c的(u,v)对放入c对应节点下,然后从i=0到100加入所有连通线段,直至结点n的指向为1(这证明着他们连通),此时的 i(i>=1) 就是需要的最少妹妹数

#include 
   
   
    
    
#include 
    
    
     
     
#include
     
     
      
      
#define MAXN 100005
#define UU 102
typedef struct Uncle
{
    int u;int v;
    struct Uncle* next;
}Uncle;/**Uncle结点,共开101个*/

int vis[MAXN];
Uncle Node[UU];
Uncle* loc[UU];/**记录下uncle 结点最后一个指针位*/

void free_(int i)
{
    /**
    由于怕这个malloc函数收不回空间,所以特地free了,
    但是呢,我一不小心free(&Node[i]),罪过罪过,害我re好多次
    */
    Uncle * a;
    Uncle * b;
    a=Node[i].next;
    while(a!=NULL){
        b=a;
        a=a->next;
        free(b);
    }
}
int main()
{
    int T;
    int n,m;
    int u,v,c_;
    int a;int b;int c;int d;
    int final_;
    int i;
    Uncle* locc;
    scanf("%d",&T);
    while(T --){
        scanf("%d%d",&n, &m);
        for(i=0;i<=n;i++){
            vis[i]=i;
        }
        for(i=0;i<=100;i++){///赋初值
            loc[i]=&Node[i];
            Node[i].next=NULL;
        }
        for(i=0;i
      
      
       
       next=malloc(sizeof(Uncle));
            loc[c_]=loc[c_]->next;
            loc[c_]->u=u
       
       
         v=u>=v?u:v; loc[c_]->next=NULL; } for(i=0;i<=100;i++){ /**从变态怪叔叔最少的开始连这个集合直到1,n同属一个集合*/ locc=Node[i].next; while(locc!=NULL){ a=locc->u; b=locc->v; c=a;d=b; /**对 u,v两个点所在集合合并*/ while(c!=vis[c]){ c=vis[c]; } while(d != vis[d]){ d=vis[d]; } vis[a]=vis[b]=vis[c]=vis[d]=d 
        
          next; } final_=n; while(final_!=vis[final_]){ final_=vis[final_]; } if(final_==1){ //printf("break;\n"); break; } } if(i){ printf("%d\n",i); } else printf("1\n"); /**这里很容易被坑的,因为如果叔叔们都不出来,也需要一个人送信过去哦*/ for(i=0;i<=100;i++){ free_(i); } } return 0; } 
         
       
      
      
     
     
    
    
   
   

题目描述

Mays王国的女王大人每天过着自由自在的生活,她最大的乐趣就是给邻国的帅气王子写信。但是最近,Mays王国的叔叔们变得很无聊,他们知道女王大人每次都把信委托给皇家小妹妹快递公司的小妹妹们,于是叔叔们给每一条路都设立了路障,只有小妹妹们给他们表演节目才会让小妹妹们过去。
在每一个路障,都有不同数量的叔叔,只有表演的小妹妹的数量不少与叔叔的数量的时候叔叔才会放她们过去。
可是七夕快要到了,Masy王国的每一个人都在给自己的情人写信。
Mays王国由n个地区组成,一些双向的道路连接着这些地区。注意两个地区之间可能有多条道路相通。
无聊的单身的beegerous已经算出了从一点到另一点送信最少需要的小妹妹的数量,为了表达对世界的不满,他脑补出了小妹妹们给任意两个点之间送信的画面,这样她们一共需要送n*(n-1)次信!如果所有的信件必须同一时间发出,这样每一次快递都需要由不同的小妹妹们来送!这样就会有好多好多小妹妹在Mays王国的道路上忙碌了。
请问,按上述脑补情形,皇家小妹妹快递公司一共需要派出多少小妹妹。

输入格式

输入第一行为数据组数T(T<=10),接下来T组数据,每组第一行为n,m,,2<=n<=10000,1<=m&lt;=100000,表示Mays王国的道路由n个节点组成,接下来m行,每行一组u,v,c表示连接节点u,v的一条无向道路,且路障上有c个叔叔,1<=u,v<=n,0<=c<=100。
输入保证任意两点之间可达。

输出格式

每组数据输出一个数字,表示小妹妹快递公司最少需要派出的小妹妹数量。

输入样例

1
3 3
1 2 1
2 3 1
1 3 3

输出样例

6

hint:
9种送快递的方式及花费为:
1 --> 2:  1
1 --> 3:  1
2 --> 1:  1
2 --> 3:  1
3 --> 1:  1
3 --> 2:  1
答案为6

 和上次那道小妹妹送快递的结构基本一样,就是处理上有不同,见代码

#include 
    
    
     
     
#include 
     
     
      
      
#include
      
      
       
       
#define MAXN 100005
#define UU 102
typedef struct Uncle
{
    int u;int v;
    struct Uncle* next;
}Uncle;/**Uncle结点,共开101个*/

int vis[MAXN];
int sum[MAXN];
Uncle Node[UU];
Uncle* loc[UU];/**记录下uncle 结点最后一个指针位*/

void free_(int i)
{
    /**
    由于怕这个malloc函数收不回空间,所以特地free了,
    但是呢,我一不小心free(&Node[i]),罪过罪过,害我re好多次
    */
    Uncle * a;
    Uncle * b;
    a=Node[i].next;
    while(a!=NULL){
        b=a;
        a=a->next;
        free(b);
    }
}
int main()
{
    int T;
    int n,m,jihe;
    int u,v,c_;
    int a;int b;int c;int d;
    int final_;
    int i;
    long long int sister;
    Uncle* locc;
    scanf("%d",&T);
    while(T --){

        scanf("%d%d",&n, &m);
        sister=0;jihe=n;
        for(i=0;i<=n;i++){
            vis[i]=i;
            sum[i]=1;
        }
        for(i=0;i<=100;i++){///赋初值
            loc[i]=&Node[i];
            Node[i].next=NULL;
        }
        for(i=0;i
       
       
        
        next=malloc(sizeof(Uncle));
            loc[c_]=loc[c_]->next;
            loc[c_]->u=u
        
        
          v=u>=v?u:v; loc[c_]->next=NULL; } for(i=0;i<=100;i++){ locc=Node[i].next; while(locc!=NULL){ a=locc->u; b=locc->v; c=a;d=b; /**对 u,v两个点所在集合合并*/ while(c!=vis[c]){ c=vis[c]; } while(d != vis[d]){ d=vis[d]; } if(c==d){ locc=locc->next; continue; } if(i==0){///别忘了,权值为0的时候,还要一个小妹妹去送信哦 final_=1; } else{ final_=i; } sister+=sum[c]*sum[d]*final_; /** *重点就在这里:新加入的边到底要走几次?它连接了两个集合,所以 *它被走的次数等于:两个集合数相乘*路径权值 */ sum[d 
         
           next; } if(jihe==1){ break; }///程序结束条件,只剩下一个集合了 } sister=sister*2; printf("%d\n",sister); for(i=0;i<=100;i++){ free_(i); } } return 0; } 
          
        
       
       
      
      
     
     
    
    




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值