codeforces 400(div2) D

题意:

现在有n个点,但是有k种类型,每种类型有ci个。现在有m条边连接这n个点,现在问对于每个type里面的点是不是可以cost为0到达自己同类型的点。如果可以输出Yes,并且找到每个类型间相互到达的最短距离。输出矩阵。

思路:

对于同一个类型的就用bfs,如果某个点能够到达跟它同类型的其他点,那么这个类型一定能够相互达到。然后缩点。用floyd就可以求解。

trick:

这道题目不难,但是后面在bfs的时候有个小地方没有注意到,在对于每个类型搜的时候flag要初始化。因为其他类型可能通过该类型的某个点到达flag被标记为1

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int c[600],flag[100010],startp[100010],sumc[600],belong[100010];
struct node{
    int u,v,x;
};
node edge[300000];
int cmp(node a,node b){
    return a.u<b.u;
}
int q[1000000];
int f[600][600];
int bfs(int sc,int ec){
    int h=0,r=0;
    q[h]=sc;
    memset(flag,0,sizeof(flag));
    flag[sc]=1;
    while(h<=r){
        int tmp=q[h];
        //flag[tmp]=1;
        int p=startp[tmp];
        //printf("%d %d p:%d %d\n",sc,ec,p,tmp);
        while(edge[p].u==tmp){
            if(edge[p].x==0){
                if(flag[edge[p].v]==0){
                    q[++r]=edge[p].v;
                    flag[edge[p].v]=1;
                    //printf("enter:%d\n",edge[p].v);
                }
            }
            p++;
        }
        h++;
    }
    for(int i=sc;i<=ec;i++){
        if(flag[i]==0){
            //printf("wa:%d\n",i);
            return 0;
        }
    }
    return 1;
}
void floyd(int n){
    for(int p=0;p<n;p++){
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(f[i][j]>f[i][p]+f[p][j])
                    f[i][j]=f[i][p]+f[p][j];
            }
        }
    }
}
main(){
    int n,m,k;
    while(scanf("%d%d%d",&n,&m,&k)!=-1){
        memset(sumc,0,sizeof(sumc));
        for(int i=0;i<k;i++){
            scanf("%d",&c[i]);
            if(i!=0){
                sumc[i]=sumc[i-1]+c[i];
            }
            else{
                sumc[i]=c[i];
            }
        }
        for(int i=0;i<m;i++){
            int cntu,cntv,cntx;
            scanf("%d%d%d",&cntu,&cntv,&cntx);
            edge[i].u=cntu-1;
            edge[i].v=cntv-1;
            edge[i].x=cntx;
            edge[i+m].u=cntv-1;
            edge[i+m].v=cntu-1;
            edge[i+m].x=cntx;
        }
        sort(edge,edge+2*m,cmp);
        memset(startp,-1,sizeof(startp));
        for(int i=0;i<2*m;i++){
            if(startp[edge[i].u]==-1){
                startp[edge[i].u]=i;
            }
        }
        /*for(int i=0;i<n;i++){
            printf("sp:%d\n",startp[i]);
        }
        printf("wa");*/
        int ans=1;
        int spc=0,epc=-1;
        memset(flag,0,sizeof(flag));
        /*for(int i=0;i<2*m;i++){
            printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].x);
        }*/
        for(int i=0;i<k;i++){
            spc=epc+1;
            epc=spc+c[i]-1;
            //printf("%d %d\n",spc,epc);
            if(bfs(spc,epc)==0){
                //printf("se %d %d\n",spc,epc);
                ans=0;
                break;
            }
        }
        //printf("wa");
        if(ans==0){
            printf("No\n");
        }
        else{
            int spc=0,epc=-1;
            for(int i=0;i<k;i++){
                spc=epc+1;
                epc=spc+c[i]-1;
                for(int j=spc;j<=epc;j++){
                    belong[j]=i;
                }
            }
            for(int i=0;i<k;i++){
                for(int j=0;j<k;j++){
                    if(i==j){
                        f[i][j]=0;
                    }
                    else{
                        f[i][j]=10000000;
                    }
                }
            }
            for(int i=0;i<2*m;i++){
                if(f[belong[edge[i].u]][belong[edge[i].v]]>edge[i].x){
                    f[belong[edge[i].u]][belong[edge[i].v]]=edge[i].x;
                }
            }
            floyd(k);
            printf("Yes\n");
            for(int i=0;i<k;i++){
                for(int j=0;j<k-1;j++){
                    if(f[i][j]==10000000){
                        printf("-1 ");
                    }
                    else{
                        printf("%d ",f[i][j]);
                    }
                }
                if(f[i][k-1]==10000000){
                    printf("-1\n");
                }
                else{
                    printf("%d\n",f[i][k-1]);
                }

            }
        }
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值