题目描述:给你k个n*m个矩阵 里面有不同的字母,每个图形可以用前面已有的矩阵变化过来(起初没有),花费是相同点不同字母的个数*w,或者全部赋值花费n*m*w;
问生成全部矩阵最少花费多少。
分析:把它构造成一个完全图,点是矩阵,边即两个举证之间的花费,所以问题转化为求最小生成树,注意dfs遍历树的时候只需要不走到父节点就行了,并不用标记所有点。
ac代码:
#include<bits/stdc++.h>
using namespace std;
struct Edge {
int u,v,w;
}edge[1100*1100];
bool cmp(Edge a,Edge b){
return a.w<b.w;
}
int n,m,k,w;
int fa[1100],diff[1100][1100];
char ch[1100][20][20];
vector <int >vc[1100];
int get_diff(char a[][20],char b[][20]){
int ret=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(a[i][j]!=b[i][j]) ret++;
return ret;
}
int getfa(int x){
if(fa[x]!=x)return fa[x]=getfa(fa[x]);
else return fa[x];
}
int Kruscal(int eg){
sort(edge,edge+eg,cmp);
for(int i=0;i<=k+1;i++){
fa[i]=i;
vc[i].clear();
}
int cnt=k+1,ans=0;
for(int i=0;i<eg;i++){
int f1=getfa(edge[i].u);
int f2=getfa(edge[i].v);
if(f1!=f2){
fa[f1]=f2;
ans+=edge[i].w;
vc[edge[i].u].push_back(edge[i].v);
vc[edge[i].v].push_back(edge[i].u);
cnt--;
if(cnt==1) break;
}
}
return ans;
}
void dfs(int u,int fa){
for(int i=0,sz=vc[u].size();i<sz;i++){
int v=vc[u][i];
if(v!=fa){
cout<<v<<' '<<u<<endl;
dfs(v,u);
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
// freopen("1.txt","r",stdin);
cin>>n>>m>>k>>w;
for(int i=1;i<=k;i++)
for(int j=0;j<n;j++)
cin>>ch[i][j];
for(int i=1;i<=k;i++)
for(int j=i+1;j<=k;j++)
diff[j][i]=diff[i][j]=get_diff(ch[i],ch[j])*w;
int eg=0;
for(int i=1;i<=k;i++){
edge[eg++]=(Edge){0,i,n*m};
for(int j=i+1;j<=k;j++)
edge[eg++]=(Edge){i,j,diff[i][j]};
}
cout<<Kruscal(eg)<<endl;
dfs(0,0);
}

京公网安备 11010502036488号