题目链接:http://codeforces.com/problemset/problem/400/D

题目大意:

  给定n个集合,m步操作,k个种类的细菌,

  第二行给出k个数表示连续的xi个数属于i集合。

  当某个种类之间两两交换的值都为0可行解,则输出所有种类之间交换的最小值;否则输出No

解题思路:当两点之间的距离为0时并查集到一个集合中,只需保证最终同一种类的细菌都在一个并查集中则是符合条件的可行解,再用FLOYD找最短路即可

  1 #include<cmath>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7 #define FFF 100005
  8 int set[FFF];
  9 int a[FFF];
 10 int sw[505][505];
 11 int cnt[505];
 12 int vis[FFF];
 13 int n,k,m;
 14
 15 int find(int x)
 16 {
 17     if(x==set[x])
 18         return x;
 19     else return set[x]=find(set[x]);
 20 }
 21
 22 void uion(int x,int y)
 23 {
 24     int l1=find(x);
 25     int l2=find(y);
 26     if(l1==l2)
 27         return;
 28     else
 29         set[l2]=l1;
 30     return;
 31 }
 32
 33 bool judge()
 34 {
 35     for(int l=1;l<=k;l++)
 36     {
 37         int tmp=-1;
 38         for(int i=cnt[l-1]+1;i<=cnt[l];i++)
 39         {
 40             if(tmp==-1)
 41                 tmp=find(i);
 42             else
 43             {
 44                 if(tmp!=find(i))
 45                     return false;
 46             }
 47         }
 48     }
 49     return true;
 50 }
 51
 52 void solve()
 53 {
 54     for(int l=1;l<=k;l++)
 55     {
 56         for(int i=1;i<=k;i++)
 57         {
 58             if(i!=l)
 59             {
 60                 for(int j=1;j<=k;j++)
 61                 {
 62                     if(j!=l&&j!=i)
 63                     {
 64                         if((sw[i][l]+sw[l][j]<sw[i][j]||sw[i][j]<0)&&sw[i][l]>=0&&sw[l][j]>=0)
 65                             sw[i][j]=sw[i][l]+sw[l][j];
 66                     }
 67                 }
 68             }
 69         }
 70     }
 71     return;
 72 }
 73
 74 void print()
 75 {
 76     for(int i=1;i<=k;i++)
 77     {
 78         sw[i][i]=0;
 79         for(int j=1;j<=k;j++)
 80         {
 81             if(j==1)
 82                 printf("%d",sw[i][j]);
 83             else
 84                 printf(" %d",sw[i][j]);
 85         }
 86         cout<<endl;
 87     }
 88     return;
 89 }
 90
 91 int main()
 92 {
 93     int i,j,now;
 94     scanf("%d%d%d",&n,&m,&k);
 95     //n为点的总个数,m为边数,k为种类数
 96     for(i=1,now=1;i<=k;i++)
 97     {
 98         int x;
 99         scanf("%d",&x);
100         // 第i种细菌有x个
101         for( j=0;j<x;j++)
102         {
103             a[j+now]=i;
104             set[j+now]=j+now;
105         }
106         now+=x;
107         cnt[i]=now-1;
108     }
109     memset(sw,-1,sizeof(sw));
110     // 两两种类之间的代价初始化成-1
111     while(m--)
112     {
113         int x,y,z;
114         scanf("%d%d%d",&x,&y,&z);
115         if(a[x]==a[y])
116         //属于同一种类
117         {
118             if(z==0)
119                 uion(x,y);
120             // 添入并查集
121         }
122         else
123         //不同种类的细菌
124         {
125             if(z==0)
126                 uion(x,y);
127             if(sw[a[x]][a[y]]==-1)
128             // 该两类之间还没有交换代价
129                 sw[a[x]][a[y]]=sw[a[y]][a[x]]=z;
130             else if(z<sw[a[x]][a[y]])
131             // 新的代价较小的情况
132                 sw[a[x]][a[y]]=sw[a[y]][a[x]]=z;
133         }
134     }
135     if(!judge())
136     // 判断同种类的细菌之间是否为0
137         printf("No\n");
138     else
139     {
140         printf("Yes\n");
141         solve();
142         // floyd找最短路
143         print();
144     }
145     return 0;
146 }
147
148 /*
149 FLOYD
150 题目大意:给定n个集合,m步操作,k个种类的细菌,
151             第二行给出k个数表示连续的xi个数属于i集合。
152             当某个种类之间两两交换的值都为0可行解
153 解题思路:当两点之间的距离为0时并查集到一个集合中,
154             最终保证同种细菌都在一个并查集中
155             再用FLOYD找最短路*/

View Code

转载于:https://www.cnblogs.com/wuwing/p/3644961.html

codeforces 400D Dima and Bacteria 并查集+floyd相关推荐

  1. codeforces 400D - Dima and Bacteria

    题目链接:http://codeforces.com/problemset/problem/400/D 题目大意:n个培养基,m种仪器,分成k种,每种细菌数量c[i],然后就给出从第i到第j个培养基转 ...

  2. Codeforces 400D Dima And Bacteria 暴力+Floyd

    题意:n点,m条带权边的无向图,每个顶点属于k类中的某一类,定义合法,同一类中的任意两点存在代价为0的路径,若合法,求出d[i][j]矩阵,表示第i类到第j类的最小代价. n,m<=1e5,k& ...

  3. CodeForces 400D Dima and Bacteria

    题意: 有n个点  它们有自己的type  给出m条边  首先要求判断可否用0费用在同样type的点中走  如果可以  用type为点建图求任意两点最短路 思路: type只有500种  最后一步可以 ...

  4. TTTTTTTTTTT 400D Dima and Bacteria 细菌 最短路

    题意: 题目大意:给出n,m和k,表示有n个细菌,m种仪器和k种细菌,给出k种细菌的数量ci,然后每个细菌按照种类排成一排(所以有第i种细菌的序号从∑(1≤j≤i-1)cj + 1 到∑(1≤j≤i) ...

  5. Codeforces 699D Fix a Tree 并查集

    原题:http://codeforces.com/contest/699/problem/D 题目中所描述的从属关系,可以看作是一个一个块,可以用并查集来维护这个森林.这些从属关系中会有两种环,第一种 ...

  6. CodeForces - 1445E Team-Building(可撤销并查集)

    题目链接:点击查看 题目大意:给出一张有 n 个点和 m 条边的图,每个点都有一个种类,共有 k 个种类,现在要从 k 个种类中每次选出两种,对所有 C( k , 2 ) 种组合单独讨论,对于选出的两 ...

  7. CodeForces - 892E Envy(可撤销并查集)

    题目链接:点击查看 题目大意:给出一张由 n 个点 m 条边组成的连通图,有 q 次询问,每次询问给出一个边集,需要判断这些边是否可以同时出现在最小生成树上 题目分析:需要用到的一个性质是,对于同一个 ...

  8. codeforces gym-101736 Farmer Faul 平衡树+并查集

    题目 题目链接 题意 给出nnn个整数,其中1≤n≤106" role="presentation" style="position: relative;&qu ...

  9. 【CodeForces - 731C】Socks(并查集,思维)

    题干: Arseniy is already grown-up and independent. His mother decided to leave him alone for m days an ...

最新文章

  1. fedora 20 PIL
  2. mysql导出二进制日志_使用mysqlbinlog提取二进制日志
  3. 我对NHibernate的感受(3):有些尴尬的集合支持
  4. 大数据架构的典型方法和方式
  5. 《深度学习要领》端到端的深度学习技术
  6. Python 语言程序设计(4-2)分支循环--无限循环
  7. python+java家庭理财个人理财管理系统记账系统
  8. python aiml开发文档,带有Python的AIML文件
  9. win10报错网络未识别的问题
  10. 小麦亩产一千八(kela)
  11. 调度工具之Azkaban 介绍
  12. 15款Chrome浏览器插件让设计师告别拖延症
  13. vue文件下载及重命名
  14. 有谁知道怎么处理微信用户头像过期问题,除了本地保存,因为不会用七牛云远程附件
  15. 新闻列表 android,- Android中实现简单的新闻列表
  16. 【Linux常用指令2】
  17. 1970年计算的时间转日期
  18. hexo设置网站的图标Favicon
  19. Apriltag原理简介及源代码
  20. JavaScript获取屏幕高度和宽度等信息

热门文章

  1. lua 实现策划需要保留的小数位数
  2. 前端路由(一) 路由,hash,history
  3. golang 值得注意的地方(2则)
  4. webapi 异步返回
  5. Xubunbtu远程桌面的tab键
  6. 微信公众平台OAuth2.0授权
  7. css3 使用SVG做0.5px 的边框细线
  8. Linux系统启动级别及grub配置(一)
  9. 测试数值计算程序要注意的问题
  10. 代码片段管理器——SnippetsLab