codeforces round 485 D 图dp

题意:

无向连通图,n点,m边。

k种货物,每个节点存放一种货物。不过k种货物你只需要s种。

依次输出以每个节点为起始点要得到s种货物所需要的最少步数。(每条边的权值为1).

思路:

n和m都是1e5,但是k为100。可以想一种遍历k的算法--->对于每一种颜色,算出每个点到它要的最小值。

dp[i][j]:i为点,j为颜色

k遍bfs即可。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5+7;
const int inf=0x3f3f3f3f;
int n,m,k,s;
int u,v;
int a[maxn];
vector<int> co[105];
struct edge{
    int v;
    int next;
}e[maxn*2];
int total=0;
int head[maxn];
void addedge(int u, int v){
    total++;
    e[total].v=v;
    e[total].next=head[u];
    head[u]=total;
}

struct node{
    int u;
    int len;
};
int vis[maxn];
node temp;
int dp[maxn][105];
void bfs(int type){
    if(co[type].size()==0)return;
    for(int i=1;i<=n;i++){
        vis[i]=0;
        dp[i][type]=inf;
    }
    queue<node> que;
    for(int i=0;i<co[type].size();i++){
        temp.u=co[type][i];temp.len=0;
        dp[temp.u][type]=0;
        que.push(temp);
        vis[temp.u]=1;
    }
    while(que.size()){
        node top=que.front();que.pop();
        u=top.u;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].v;
            if(vis[v])continue; 
            dp[v][type]=min(dp[v][type], dp[u][type]+1);
            temp.u=v;temp.len=dp[v][type];
            vis[v]=1;
            que.push(temp);
        }
    }
}
int main()
{
    freopen("in.txt","r",stdin);
    scanf("%d%d%d%d",&n,&m,&k,&s);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        co[a[i]].push_back(i);
    } 
    
    while(m--){
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    for(int i=1;i<=k;i++)
        bfs(i);
    int ans;
    for(int i=1;i<=n;i++){
        sort(dp[i]+1, dp[i]+1+k);
        ans=0;
        for(int j=1;j<=s;j++){
            ans+=dp[i][j];
        }
        printf("%d ",ans);
    }
}

 

posted @ 2020-04-21 21:25  aaaaaaaaaaaaaa123  阅读(127)  评论(0)    收藏  举报