题目:

题目描述
给你一个 N 个结点的有向图,而且给你一个 N * N 的邻接矩阵,表示两个结点之间是否有边。star 是这样定义的 : 它有一个中心结点,并且中心结点至少有 3个出度,出度用于计算 star 的光芒程度。 对于一个结点V 来说,它可以有多颗star, 记为结点 V 的 star number. 例如, 如果结点V 的出度是 5, 那么结点V的 star number 通过计算等于16, 因为以 V 为中心结点而且光芒程度是 3 的有 C(5,3) =10 颗 star, 光芒程度是 4 的有 C(5,4)=5 颗 star,光芒程度是 5 的有 C(5,5)=1 颗 star. 所以,结点 V 共有 10 + 5 + 1 = 16 颗不同的 star。如果一 个结点的出度是X,且 X>=3,那么该结点共有:C(X,3) + C(X,4) + C(X,5) + …+ C(X,X)颗不同的 star。上面提到的C 其实就是组合数。 下面我们定义有向图中的全明星路径:如果某条路径同时满足下面两个条件,则 认为是全明星路径:

(1) 路径上的任意一个结点的 star number 大于 0 且不超过给定的整数 G.

(2) 路径上的结点 Vi 和 Vi+1,要保证Vi+1 的star number 不小于 Vi 的star number。

你的任务是:计算给出的有向图,最长的全名星路径有多少个结点。如果全明星 路径可以无限长,输出-1.如果没有全明星路径 (也就是给出的图中的所有结点的 star number 要么是0,要么大于G),则输出 0。

输入输出格式
输入格式:
多组测试数据。
第一行:一个整数 ng, 1 <= ng <= 5. 表示有 ng 组测试数据。 每组测试数据格式如下:
第一行:两个整数 N、C. 2 <= N <= 50, 1 <= G <= 10^9. 接下来有N 行,每行有 N 列,表示邻接矩阵,如果有边则是 1,否则是 0。保证 第i 行的第i 个是 0.

输出格式:
最长的全名星路径有多少个结点。
ng 行,每行对应一组输入数据。

输入输出样例
输入样例#1: 
2  
5 1000 
01110  
10111  
00000  
00000  
00000  
4 1 
0111  
0000  
0000  
0000 
输出样例#1: 
2
1
说明
第一组测试数据:结点 0 的star number 是 1, 结点 1 的star number 是 5,其他结点的star number 都是 0

思路:
首先预处理组合数,然后建图。
最开始以为是无向图,就判了环写了树的直径,造就了比赛A题爆0的惨剧。
其实判环加上floyd最长路就好了。

代码:

#include<bits/stdc++.h>
using namespace std;

#define maxn 50

const int c[maxn+5]={0,0,0,1,5,16,42,99,219,466,968,1981,4017,8100,16278,32647,65399,130918,261972,524097,1048365,2096920,4194050,8388331,16776915,33554106,67108512,134217349,268435049,536870476,1073741358,2147483151};

int n,G;
int a[maxn+5][maxn+5];

int w[maxn+5];

int g[maxn+5][maxn+5];
int vis[maxn+5],vis2[maxn+5];

bool dfs(int x) {
	if(vis2[x]) return true;
	else vis2[x]=true;
	int s=0;
	for(int i=1;i<=n;i++) {
		if(g[x][i]) s|=dfs(i);
	}
	vis2[x]=false;
	return s;
}

int main() {
	int T;
	scanf("%d",&T);
	
	while(T--) {
		scanf("%d%d",&n,&G);
		for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%1d",&a[i][j]);
		memset(w,0,sizeof(w));
		memset(g,0,sizeof(g));
		memset(vis,0,sizeof(vis));
		
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=n;j++) {
				if(a[i][j]) w[i]++;
			}
		}
		
		bool flg=0;
		
		for(int i=1;i<=n;i++) {
			if(w[i]<3||w[i]>31||c[w[i]]>G) continue;
			flg=true;
			for(int j=1;j<=n;j++) {
				if(w[j]<3||w[j]>31||c[w[j]]>G||c[w[j]]<c[w[i]]) continue;
				if(a[i][j]) g[i][j]=1;
			}
		}
		
		int ans=0;
		
		if(!flg) {printf("0\n");goto END;}
		
		for(int i=1;i<=n;i++) {
			memset(vis2,0,sizeof(vis2));
			if(!vis[i]) if(dfs(i)) {printf("-1\n");goto END;}
		}
		
		for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(!g[i][j]) g[i][j]=-1000;
		
		for(int k=1;k<=n;k++) 
			for(int i=1;i<=n;i++) 
				for(int j=1;j<=n;j++) 
					if(g[i][k]+g[k][j]>g[i][j]) g[i][j]=g[i][k]+g[k][j];

		for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) ans=max(ans,g[i][j]);
		
		printf("%d\n",ans+1);
		
		END:;
	}
	
	return 0;
}