【BZOJ 4878】[Lydsy2017年5月月赛] 挑战NP-Hard

相关链接

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4878

解题报告

我们搞出$DFS$生成树
如果树高大于$k$,那么显然可以找出长度为$k$的简单路径
如果树高$\le k$的话,因为非树边一定是返祖边,所以把深度作为颜色就可以$k$染色了

Code

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

const int N = 1009;
const int M = 20009;

int n,m,k,E,head[N],nxt[M],to[M];
int DONE,fa[N],dep[N];

inline int read() {
	char c=getchar(); int f=1,ret=0;
	while (c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while (c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();}
	return ret * f;
}

inline void AddEdge(int u, int v) {
	to[++E] = v; nxt[E] = head[u]; head[u] = E;
	to[++E] = u; nxt[E] = head[v]; head[v] = E;
}

void DFS(int w, int f) {
	dep[w] = dep[f] + 1;
	fa[w] = f;
	if (dep[w] > k) {
		DONE = 1;
		printf("path ");
		for (; 1; w = fa[w]) {
			printf("%d ", w);
			if (w == fa[w]) {
				break;
			}
		}
		cout<<endl;
	} else {
		for (int i = head[w]; i && !DONE; i = nxt[i]) {
			if (!dep[to[i]]) {
				DFS(to[i], w);
			}
		}
	}
}

int main() {
#ifdef DBG
	freopen("11input.in", "r", stdin);
#endif
	for (int T = read(); T; T--) {
		memset(head, 0, sizeof(head));
		n = read(); m = read(); 
		k = read(); E = DONE = 0;
		for (int i = 1; i <= m; i++) {
			AddEdge(read(), read());
		}
		memset(dep, 0, sizeof(dep));
		for (int i = 1; i <= n && !DONE; ++i) {
			if (!dep[i]) {
				DFS(i, i);
			}
		}
		if (!DONE) {
			printf("color ");
			for (int i = 1; i <= n; ++i) {
				printf("%d ", dep[i]);
			}
			cout<<endl;
		}
	} 
	return 0;
}

【TopCoder SRM713】DFSCount

相关链接

题目传送门:https://community.topcoder.com/stat?c=problem_statement&pm=14588&rd=16882

题目大意

给定一个$n(n \le 14)$的简单无向图,问$DFS$序总共可能有多少种不同情况

解题报告

这是一个非常妙妙的$DP$
考虑定义$f_{i,j}$表示当前在第$i$个点,已经走过的点压成二进制状态为$j$
但我们发现这样无法实现$DFS$模拟当中的退回操作

但我们考虑一下$DFS$树:这货是没有横叉边的,只有返祖边
这意味着我们如果决定朝一个方向走,那么一定是把那一个连通块走完才会退回来
于是我么可以不一步一步转移,我们可以把一整块连通块一起转移,这样就不需要模拟$DFS$的回退操作了

至于这份代码是:$O(n^2 2^n)$的
实现得精细一点可以做到$O(n 2^n)$

Code

#include<bits/stdc++.h>
#define LL long long
using namespace std;
 
int n,id[15];
bool g[15][15],vis[15];
LL f[15][17000],pw[15],pol[15];

class DFSCount {
    public:
    	long long count(vector<string> G) {
    		pw[0] = 1;
    		for (int i=1;i<=14;i++) {
				pw[i] = pw[i-1] * i;
			}
    	    n = G.size();
    	    for (int i=0;i<n;i++) {
				for (int j=0;j<n;j++) {
					if (G[i][j] == 'Y') g[i][j] = 1;
					else g[i][j] = 0;
				}
			}
    	    memset(f, 0, sizeof(f));
			for (int i=0;i<n;i++) {
				f[i][(1<<n)-1] = 1;
			}
			for (int sta=(1<<n)-2;sta>0;sta--) {
				for (int i=0;i<n;i++) {
					if (!(sta&(1<<i))) continue;
					for (int j=0;j<n;j++) {
						vis[j] = (sta & (1 << j));
					}
					int cnt = 0;
					for (int j=0;j<n;j++) {
						if (g[i][j] && !(sta&(1<<j))) {
							if (!vis[j]) {
								DFS(j, ++cnt);
								pol[cnt] = 0;
							}
							pol[id[j]] += f[j][(1<<j)|sta];
						}
					}
					f[i][sta] = pw[cnt];
					for (int j=1;j<=cnt;j++) {
						f[i][sta] *= pol[j];
					}
				}
			}
			LL ret = 0;
			for (int i=0;i<n;i++) {
				ret += f[i][1<<i];
			}
			return ret;
   		}
   	private:
   		void DFS(int w, int ID) {
			vis[w] = 1; 
			id[w] = ID;
			for (int i=0;i<n;i++) {
				if (g[w][i] && !vis[i]) {
					DFS(i, ID);
				} 
			}   
		}
};