题解:CF436C Dungeons and Candies
CF436C 题解
看完题面很容易想到用最小生成树解,看大家都是用 kruscal 做的,我这边提供一个 prim 的做法。
思路
传输有两种方式,一种代价为 \(n \times m\),一种代价为两文件不同的字符个数 \(\times w\)。因为每个文件都可以用第一种方式传输,所以我们将 dis 数组初始化为 \(n \times m\)。然后用第二种方式更新 dis 数组,保存每一次用来更新的中间点即为 answer。注意要用 pair 储存 dis 数组,key1 是距离,key2 是与其比对的前面文件的下表,特殊的,当 key2 为 0 时此文件为第一种传输方式。因为是稠密图所以用朴素的 prim。
code
#include <bist/stdc++.h>
using namespace std;
#define ll long long
#define rg register int
#define N 10100
int n, m, k, w;
char c[N][20][20];
vector<bool> vis(N);
pair<int, int> dis[N];
struct Node{
int x, y;
};
int cnt;
vector<Node> ans(N);
int Ans;
inline int ct(int &a, int &b){
int cnt = 0;
for(rg i = 1; i <= n; i++)
for(rg j = 1; j <= m; j++)
if(c[a][i][j] ^ c[b][i][j])cnt++;
return cnt * w;
}
void prim(){//板子
//ans[1] = {1, 0};
for(rg i = 1; i <= k; i++){
int tot = 1e5, opt = 0;
for(rg j = 1; j <= k; j++)
if(!vis[j] && dis[j].first < tot)
tot = dis[j].first, opt = j;
if(opt == 0)continue;
Ans += tot;
vis[opt] = true;
ans[++cnt] = {opt, dis[opt].second};
//储存中间点即为答案
int sum;
for(rg j = 1; j <= k; j++){
sum = ct(opt, j);
if(sum < dis[j].first)dis[j].first = sum, dis[j].second = opt;
}
}
return ;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> k >> w;
for(rg i = 1; i <= k; i++)
dis[i].first = n * m;//初始化
for(rg i = 1; i <= k; i++)
for(rg j = 1; j <= n; j++)
for(rg p = 1; p <= m; p++)
cin >> c[i][j][p];//输入
prim();
cout << Ans << "\n";
for(rg i = 1; i <= cnt; i++)
cout << ans[i].x << ' ' << ans[i].y << "\n";
return 0;
}

浙公网安备 33010602011771号