题目
【问题描述】
给定n只虫子,序号为1~n,每只虫子有di条触手(各di值可以不相同),且每条触手对应一个正整数,代表该触手的臂力。问能否将这n只虫子连成一个网络,保证每只虫子的每条触手都连接到另一只虫子的某条触手。注意,只有当两只虫子各有一条触手的臂力值为w,才能将这两只虫子的这两条触手连起来、合并成一条触手。
【输入形式】
输入文件包含多个测试数据。每个测试数据第1行为正整数n,5≤n≤20,代表虫子的数目;接下来有n行,第i行首先是一个正整数,表示第i个虫子的触手数目di,1≤di≤n-1,接下来有di个正整数wi1, wi2, …,表示这di条触手的臂力,wij的范围为[1,99],用空格隔开。n=0代表输入结束。测试数据保证如果能连成一个网络,则网络中任何两条触手的臂力都不相同,任何两个虫子之间最多只有一条触手相连,任何虫子都不会有触手连接到自己;不保证其他不合理的情形。
【输出形式】
对每个测试数据,首先输出"case #: ",#代表测试数据序号,从1开始计起;如果不能构成网络,输出no;否则首先输出yes,然后输出n行,每行有n个数字(或INF),主对角线上的位置均为数字0,此外第i行、第j列上的数字代表第i虫子和第j个虫子相连的触手的臂力值,如果为INF,则表示这两个虫子没有触手相连;这些数字或INF均占3个字符宽度,每两个数字或INF之间用一个空格隔开,即最后一个数字或INF之后没有空格。
【样例输入】
7
2 28 10
3 28 16 14
2 16 12
3 12 22 18
3 22 25 24
2 10 25
3 14 18 24
9
6 10 2 52 95 72 35
3 57 35 52
4 50 66 92 55
1 97
2 26 89
8 97 60 42 66 42 26 72 2
6 10 16 79 17 13 79
6 60 19 13 19 95 17
6 55 92 57 50 16 89
0
【样例输出】
case 1: yes
0 28 INF INF INF 10 INF
28 0 16 INF INF INF 14
INF 16 0 12 INF INF INF
INF INF 12 0 22 INF 18
INF INF INF 22 0 25 24
10 INF INF INF 25 0 INF
INF 14 INF 18 24 INF 0
case 2: no
【样例说明】
【评分标准】
代码
#include<iostream>
using namespace std;
#include<iomanip>
const int INF = 0x3f3f3f3f;
const int n=25;
bool check(int Map[][n],int N) //利用最短路径算法,判断能否形成网络,如果能形成网络,则一个点应该都有到其他点的最短路径,即除了到本身为0外,到其他点的距离不为INF
{
int succ[n]={0};
succ[1]=1;
for(int i=0;i<N-2;i++)
{
int Min = INF;
int index =0;
for(int j=1;j<=N;j++)
{
if(succ[j] == 0 && Map[1][j]<Min)
{
Min = Map[1][j];
index = j;
}
}
succ[index]=1;
for(int j=1;j<=N;j++)
{
if(succ[j] == 0 && (Min+Map[index][j])<Map[1][j])
{
Map[1][j] = Min+Map[index][j];
}
}
}
for(int i=1;i<=N;i++)
{
if(Map[1][i] == INF)
return false;
}
return true;
}
int main()
{
int N;
int num=1;
cin>>N;
while(N!=0)
{
int nosame=0; //用来判断两个虫子是否有两条触手相连
int hand[n][n]={0}; //存储虫子的臂力
for(int i=1;i<=N;i++)
{
int m;
cin>>m;
for(int j=1;j<=m;j++)
cin>>hand[i][j];
}
int Map[n][n]={0}; //存储能够相连的虫子之间的臂力
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
Map[i][j]=INF;
Map[i][i]=0;
}
for(int i=1;i<=N;i++)
{
for(int j=1;j<N;j++)
{
if(hand[i][j] == 0) //每个虫子的触手数量不同,统一遍历只要当臂力为0时则该虫子所有触手已经遍历完
break;
int k=1;
for(;k<=N;k++) //遍历其他虫子
{
if(k!=i) //不能与自身相连
{
int b=0; //用来判断是否找到可以与第i号虫子相连的触手
int l=1;
for(;l<N;l++)
{
if(hand[k][l] == 0)
break;
if(hand[i][j] == hand[k][l]) //找到
{
b=1;
break;
}
}
if(b==1)
{
if(Map[i][k]!=INF) //如果第i号虫子与第k号虫子已经相连,说明不止一条触手可以使得它们相连,所以不满足题意,直接退出循环,输出no
{
nosame=1;
break;
}
Map[i][k]=hand[i][j];
break;
}
}
}
if(k>N) //第i号虫子的一条触手遍历了其他所有虫子后依然没能找到与之匹配的触手,不满足题意,退出循环,借助nosame=1,输出no
nosame=1;
if(nosame ==1 )
break;
}
if(nosame ==1)
break;
}
if(nosame ==1)
{
cout<<"case "<<num<<": ";
cout<<"no"<<endl;
cin>>N;
num++;
continue;
}
int SubMap[n][n]; //Map要进入check函数进行检测是否满足网络,会被修改,所以使用SubMap来保存修改前的状态,用来输出
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
SubMap[i][j] = Map[i][j];
}
cout<<"case "<<num<<": ";
if(check(Map,N))
{
cout<<"yes"<<endl;
for(int i=1;i<=N;i++)
{
for(int j=1;j<=N;j++)
{
if(SubMap[i][j] == INF)
cout<<setw(3)<<"INF";
else
cout<<setw(3)<<SubMap[i][j];
if(j<N)
cout<<" ";
}
cout<<endl;
}
}
else
cout<<"no"<<endl;
cin>>N;
num++;
}
}