题意:
k个点,每个点都是一个n * m的char型矩阵。对与每个点,权值为n * m或者找到一个之前的点,取两个矩阵对应位置不同的字符个数乘以w。找到一个序列,使得所有点的权值和最小并输出。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 1005
#define MAXN 2005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std;
int n,m,k,w;
int dist[maxn];
char MP[maxn][11][11];
int mp[maxn][maxn];
int pre[maxn];
int path[maxn][2]; //记录路径
int vis[maxn];
int num;
int Different(char a[11][11],char b[11][11])//求两个矩阵不同的个数
{
int cnt=0;
for (int i=0;i<n;i++)
for (int j=0;j<m;j++)
if (a[i][j]!=b[i][j])
cnt++;
return cnt;
}
int prim() //prim算法求最小生成树
{
int pos,ans=0,minn;
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
for (int i=1;i<=k;i++) dist[i]=n*m;
num=0;
for(int i=1;i<=k;i++)
{
minn=INF;
pos=-1;
for(int j=1;j<=k;j++)
{
if(!vis[j]&&minn>dist[j])
{
pos=j;
minn=dist[j];
}
}
ans+=dist[pos];
vis[pos]=1;
if(pos==-1)
break;
if (dist[pos]==n*m) //这种情况下直接传输过去花费较小
{
path[num][0]=pos;
path[num++][1]=0;
}
else //否则通过之前的已经传输过去的将它传过去
{
path[num][0]=pos;
path[num++][1]=pre[pos];
}
for(int j=1;j<=k;j++)
{
if(!vis[j]&&dist[j]>mp[pos][j])
{
dist[j]=mp[pos][j];
pre[j]=pos;
}
}
}
return ans;
}
int main()
{
int i,j;
while (~scanf("%d%d%d%d",&n,&m,&k,&w))
{
for (i=1;i<=k;i++)
{
for (j=0;j<n;j++)
scanf("%s",MP[i][j]);
}
for (i=1;i<=k;i++) //建图
{
for (j=i+1;j<=k;j++)
mp[i][j]=mp[j][i]=min(n*m,Different(MP[i],MP[j])*w);
mp[i][i]=0;
}
printf("%d\n",prim()); //输出最小花费
for (i=0;i<num;i++) //输出方案
printf("%d %d\n",path[i][0],path[i][1]);
}
return 0;
}