標籤:blog os io for div line amp log
題意:給你n個點,是否可以分成k塊,如果可以分,就求任意兩塊之間的最短路。如果兩點距離為0即為一塊,但是還有一個條件,我一開始沒看清,
以為只要是可以滿足K塊就行,與先後順序無關,其實不然。如果是分成3塊,第一塊是5,第二塊是3,第三塊是4,那麼1到5號點都是第一塊的,
6到8號點時第二塊的,9到11號點是第三塊的,如果不滿足這種就是錯誤的。有點坑啊,英語是硬傷啊!!!!!
思路:先用並查集如果滿足w=0;那麼就是一個集合,再按順序求出那些點應該是在那個塊。再求塊到塊之間如果有路徑,就儲存最短的那條,
判斷是不是都滿足分塊的要求,如果滿足,就跑一次Floyd,求得任意兩塊之間的距離。
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxm = 100009;const int maxn = 600;const int inf = 1<<29;struct node{int u,v,w;}eg[maxm];int fa[maxm];int dis[maxn][maxn];int Count[maxn]; int hash[maxn];int sum[maxn];int n,m,k;int pre[maxm];void init(){int i,j;for(i=0; i<= n; i++) fa[i] = -1;for(i =0;i<maxn;i++){for(j=0;j<maxn;j++)dis[i][j] = inf;dis[i][i] = 0;}}int find(int x){int p;for(p =x;fa[p] >= 0;p = fa[p]);while(x != p){int temp = fa[x];fa[x] = p;x = temp;}return p;}void Union(int a,int b){int x = find(a);int y = find(b);if(x == y) return ;int temp = fa[x] + fa[y];if(fa[x] > fa[y])fa[x] = y, fa[y] = temp;elsefa[y] = x, fa[x] = temp;}void floyd(){for(int z =0; z < k; z++){for(int i= 0; i < k; i++){for(int j = 0;j < k; j++){if(dis[i][j] > dis[i][z] + dis[z][j])dis[i][j] = dis[i][z] + dis[z][j];}}}}inline int min(int a,int b){return a < b ? a : b;}int main(){int i;while(~scanf("%d%d%d",&n,&m,&k)){init();sum[0] = 0;for(i=1;i<=k;i++){scanf("%d",&Count[i]);sum[i] =sum[i-1] + Count[i];}for(i=0;i<m;i++){scanf("%d%d%d",&eg[i].u,&eg[i].v,&eg[i].w);if(eg[i].w == 0)Union(eg[i].u,eg[i].v);int u=lower_bound(sum+1,sum+k+1,eg[i].u)-sum;u--; int v=lower_bound(sum+1,sum+k+1,eg[i].v)-sum;v--;if(u == v)continue;dis[u][v] = dis[v][u] = min(dis[u][v],eg[i].w);} memset(pre,0,sizeof(pre)); int flag=1; for(i=1;i<=n;i++) { int posu=lower_bound(sum+1,sum+k+1,i)-sum; int u=find(i); if(pre[posu]) { if(u!=pre[posu]) { flag=0; break ; } } else { pre[posu]=u; } } if(flag) printf("Yes\n"); else { printf("No\n"); continue ; }floyd();for(i=0;i<k;i++){for(int j=0; j < k;j++){if(dis[i][j] >= inf)dis[i][j] = -1;printf("%d ",dis[i][j]);}printf("\n");}}return 0;}