【随机编号】【 2019 Multi-University Training Contest 8】1008.Andy and Maze

Description

  • 给一个无向图,每条边有长度,问最长的点数为k的简单路径的长度。
  • n<=1e4,m<=1e4,k<=6,极限数据组数<=5

Solution

  • 一种神奇的思路。
  • 给每一个点随机一个在k以内的颜色,再根据颜色进行状压DP并保证路径上的颜色都是不一样的(这样强行确定为简单路径)
  • 这样做一次的成功率为k!kkfrac{k!}{k^k},约为0.16,随机很多次(看情况而定)后答案就有可能正确了。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 10005
#define maxm 20005
#define Time 200
#define inf 1e9
using namespace std;

int T,n,m,k,i,j,x,y,z,S;
int em,e[maxm],nx[maxm],ls[maxn],ec[maxm];
int col[maxn],f[maxn][1<<6],ans;

void Max(int &x,int y){x=max(x,y);}

void insert(int x,int y,int z){
	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em; ec[em]=z;
	em++; e[em]=x; nx[em]=ls[y]; ls[y]=em; ec[em]=z;
}

int nows=0,a=3,b=267,c=19,d=983,mo=19260817;
void rd(){
	for(i=1;i<=n;i++){
		nows=(a*nows*nows*nows+b*nows*nows+c*nows+d)%mo;
		nows=(nows+mo)%mo;
		col[i]=nows%k;
	}
}

int main(){
	scanf("%d",&T);
	while (T--){
		scanf("%d%d%d",&n,&m,&k);
		em=0;memset(ls,0,sizeof(ls));
		for(i=1;i<=m;i++){
			scanf("%d%d%d",&x,&y,&z);
			insert(x,y,z);
		}
		ans=-inf;
		for(int time=1;time<=Time;time++){
			rd();
			memset(f,128,sizeof(f));
			for(i=1;i<=n;i++) f[i][1<<col[i]]=0;
			for(S=1;S<(1<<k)-1;S++) {
				for(x=1;x<=n;x++) if (f[x][S]>-inf)
					for(i=ls[x];i;i=nx[i]) if (!(S&(1<<col[e[i]]))) 
						Max(f[e[i]][S^(1<<col[e[i]])],f[x][S]+ec[i]);
			}
			for(i=1;i<=n;i++) ans=max(ans,f[i][(1<<k)-1]);
		}
		if (ans==-inf) printf("impossible
"); else printf("%d
",ans);
	}
}
原文地址:https://www.cnblogs.com/DeepThinking/p/13090971.html