Codeforces Round #485 (Div. 2)D. Fair

这里写图片描述
Examples
inputCopy
5 5 4 3
1 2 4 3 2
1 2
2 3
3 4
4 1
4 5
outputCopy
2 2 2 2 3
inputCopy
7 6 3 2
1 2 3 3 2 2 1
1 2
2 3
3 4
2 5
5 6
6 7
outputCopy
1 1 1 2 2 1 1

题意:n个城市,m条边(无向),保证每个城市都是联通的,每个城市有且只有一种颜色,共有k种颜色。从城市i出发,要获得s种颜色,且要保证代价最小,获取某种颜色的代价为两个城市间的最短路径
分别求从每个城市出发获取s种颜色的最小代价。

思路:
1.把颜色为c1=<c<=k)的城市放在同一层(放入队列),进行bfs,即可得到所有城市获取颜色c的最小代价
2.进行kBFS,就可以每个城市获取每种颜色的最小代价
3.对于每一个城市,取代价最小的前k种颜色。
我是把颜色c,看作城市n+c,然后对颜色为c的城市(假设为u)建一条有向边,即建边<n+c,u>;然后从每种颜色n+c(1=<c<=k)进行BFS
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<vector>
#include<algorithm>
#define scan(i) scanf("%d",&i)
#define scanl(i) scanf("%I64d",&i)
#define print(i) printf("%d",i)
#define printl(i) printf("%I64d",i)

#define py() puts("Yes")
#define pn() puts("No")
#define repi(LL,RR) for(long long i=LL;i<=RR;i++)
#define repj(LL,RR) for(long long j=LL;j<=RR;j++)
#define rpei(RR,LL) for(long long i=RR;i>=LL;i--)
#define rpej(RR,LL) for(long long j=RR;j>=LL;j--)
#define cout(nnn) cout<<nnn<<"----"<<endl;
using namespace std;
typedef long long ll;
int n,m,k,s;

vector<int>g[100005+200],res[100005+200];
queue<int>q;
bool vis[100005+200];
void ins(int x ,int y){
    g[x].push_back(y);
}
void bfs(int st){
    repi(1,n)vis[i]=0;
    q.push(st);
    int dp=-2;
    while(!q.empty()){

        int len=q.size();
        dp++;
        while(len--){
        int tp=q.front();
        //cout<<tp<<" :tp"<<endl;
        q.pop();
        vis[tp]=1;
        res[tp].push_back(dp);
        int l=g[tp].size();
        repi(0,l-1){
        int id=g[tp][i];
        if(!vis[id]){
            vis[id]=1;
            q.push(id);
        }
        }


        }

    }

}
int main(){

    scan(n);scan(m);scan(k);scan(s);
    repi(1,n){
        int cl;
    scan(cl);
    ins(n+cl,i);
    }

    repi(1,m){
    int x,y;
    scan(x);scan(y);
    ins(x,y);
    ins(y,x);
    }

    repi(1,k){
    bfs(n+i);
}

repi(1,n){
sort(res[i].begin(),res[i].end());
ll ans=0;
repj(0,s-1){
ans+=res[i][j];
}
printf("%I64d",ans);
if(i!=n)printf(" ");
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值