博主本来只想虐虐NOIP级别的暴力的.........
1. 本题状态很简单 , 哪些边用了 , 现在各点在哪里 , 把vector状态压缩成一个long long(代码中的ull 是 long long).
2. 转移的思路不复杂 , 看看哪些点能够从某一房间转移到另外一些房间 (不知道不预处理的版本能不能过 , 但是博主进行了一次预处理)
写写吧 , 虽然肯定超时 , 但是正解离你将要写的代码修改的不过3,4行 , 写完后尝试以下数据
就这样写 , 样例跑的很快 , 但是有一组数据肯定过不了
10 10
(博主想了各种优化方法 , 但是这个复杂度需要的优化不是常数级别的 , 也就是题目中的hint 所说的)
观察发现 , 其实状态是很有限的 , 因为很多路都只能经过一次 , 有用的状态尤其有限 (比如上述数据中从1到10然后回到1肯定是无用状态)
那该怎么处理呢? 请思考些时间 , 提示: 无用的状态是什么造成的
如果有思路了就动手吧 , 下面是代码 , 余下的所有分析在代码后
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <string> #include <vector> #include <deque> #include <stack> #include <algorithm> #include <set> #include <queue> #include <list> using namespace std; typedef long long ull; const int maxn = 12; const int maxm = 12; int n , m; int u[maxm] , v[maxm] , w[maxm]; vector<int> g[maxn]; int allow[maxm][1<<maxn]; ull q[10000000]; set<ull> dic; ull encode(vector<int>& s) { ull res = 0; for(int i=1;i<s.size();i++) res = res*11+s[i]; res = res*1200+s[0]; return res; } void decode(vector<int>& s , ull v) { s[0] = v%1200; v/=1200; for(int i=(int)s.size()-1;i>=1;i--) s[i] = v%11 , v/=11; } int reachable[maxn][maxn]; int main(int argc, char *argv[]) { while(cin>>n>>m) { dic.clear(); memset(allow, 0, sizeof(allow)); for(int i=1;i<=n;i++) g[i].clear(); memset(reachable, 0, sizeof(reachable)); for(int i=1;i<=m;i++) { cin>>u[i]>>v[i]>>w[i]; if(w[i]) g[u[i]].push_back(i); else reachable[u[i]][v[i]] = 1; } for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) reachable[i][j] |= ( reachable[i][k] && reachable[k][j] ); for(int i=1;i<(1<<9);i++) if(__builtin_popcount(i)>=3 && __builtin_popcount(i)<=5) { int num = 0; for(int j=1;j<=9;j++) if(i&(1<<(j-1))) num+= j; while(num>=10) num = num/10+num%10; for(int j=1;j<=m;j++) if(w[j]==num) allow[j][i] = 1; } for(int j=1;j<=m;j++) if(w[j]==0) for(int i=1;i<512;i++) allow[j][i] = 1; int book[maxn]; vector<int> beg; set<int> ans; int Max = 0; beg.push_back((1<<m)-1); for(int i=1;i<=9;i++) beg.push_back(1); int l = 0 , r = 0; q[r++] = encode(beg); dic.insert(encode(beg)); while(l!=r) { vector<int> now = beg , ne; decode(now, q[l++]); memset(book, 0, sizeof(book)); for(int i=1;i<now.size();i++) book[now[i]] |= (1<<(i-1)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(reachable[i][j]) book[j] |= book[i]; if(book[n] && __builtin_popcount(book[n])>Max) { Max = __builtin_popcount(book[n]); ans.clear(); ans.insert(book[n]); } else if(book[n] && __builtin_popcount(book[n])==Max) if(ans.count(book[n])==0) ans.insert(book[n]); for(int i=1;i<=n;i++) for(int j=0;j<g[i].size();j++) { int way = g[i][j] , to = v[way]; if(!(now[0]&(1<<(way-1)))) continue; for(int s = book[i];s>0;s = (s-1)&book[i]) if(allow[way][s]) { ne = now; for(int l=1;l<=9;l++) if(s& (1<<(l-1))) ne[l] = to; if(w[way]) ne[0]^= 1<<(way-1); ull hashNow = encode(ne); if(dic.count(hashNow)) continue; dic.insert(hashNow); q[r++] = encode(ne); } } } vector<string> output; for(set<int>::iterator i=ans.begin();i!=ans.end();++i) { int now = *i; string ins; for(int j=1;j<=9;j++) if(now&(1<<(j-1))) ins = ins+((char)(j+'0')); output.push_back(ins); } sort(output.begin(), output.end()); cout<<Max; for(int i=0;i<output.size();i++) cout<<" "<<output[i]; cout<<endl; } return 0; }
剩下的就是floyd判通 , 然后稍稍修改代码就可以啦