CodeForces - 986A Fair

有n個商店,n個商店有m條雙向小路相連,在這n個商店裏共有k種不同商品,每個商店只有一種商品,每條路的權重都爲1。現問你從每個商店出發,買夠k種商品中的s種商品所需的最小代價,每個商店可以同時派出多個人買不同商品,買夠即可。

輸入
對於每一組輸入包含四個數字n ,m, k,s (1<=n<=m<=1e5 , 1<=s<=k<=min(n,100))
分別代表商店數,小路數,商品種數,需要的商品數。
接下來n個數 a1,a2…an (1<=ai<=k),ai代表第i個商店的商品編號。
接下來m行小路(u,v),u≠v,代表商店u和v之間有小路連接。

輸出
輸出n個數字,第i個數字代表從商店i出發買夠s種商品所需的最小代價。

樣例輸入

5 5 4 3
1 2 4 3 2
1 2
2 3
3 4
4 1
4 5
7 6 3 2
1 2 3 3 2 2 1
1 2
2 3
3 4
2 5
5 6
6 7

樣例輸出

2 2 2 2 3 
1 1 1 2 2 1 1 

bfs+貪心

分析:N是1e5,直接對每個點搜肯定超時。而K的範圍很小,而且1-K全部覆蓋。對所有1-K的值BFS,用二維數組dp[i][j]記錄i點要獲取編號爲j的物品最少走過的路程,並對每個點取最小的S個物品對應的路徑。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn =1e5+5;
int a[maxn];
int ans[maxn];
vector<int> G[maxn];
bool vis[maxn];
int d[maxn][305];

void BFS(int val,int N){
    memset(vis,0,sizeof(vis));
    queue<int> Q;
    for(int i=1;i<=N;++i){
        if(a[i]==val){
            vis[i]=true;
            Q.push(i);
        }
    }
    while(!Q.empty()){
        int x =Q.front();Q.pop();
        for(int i=0;i<G[x].size();++i){
            int v = G[x][i];
            if(!vis[v]){
                vis[v] = true;
                d[v][val] = d[x][val]+1;
                Q.push(v);
            }
        }
    }
}

int main(){
    int N,M,K,S,u,v;
    while(scanf("%d%d%d%d",&N,&M,&K,&S)!=EOF){
        for(int i=1;i<=N;++i) G[i].clear();
        memset(d,0,sizeof(d));
        for(int i=1;i<=N;++i) scanf("%d",&a[i]);
        for(int i=1;i<=M;++i){
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        for(int i=1;i<=K;++i){
            memset(vis,0,sizeof(vis));
            BFS(i,N);
        }
        for(int i=1;i<=N;++i){
            sort(d[i]+1,d[i]+K+1);
            ans[i]=0;
            for(int j =1;j<=S;++j){
                ans[i]+=d[i][j];
            }
        }
        for(int i=1;i<N;++i) printf("%d ",ans[i]);
        printf("%d\n",ans[N]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章