题目:Influence
题意:其实就是给定一个有向无环图,给定一个点集,问这些点里面从哪个出发能访问到的点最多。
由于这是一个图,不能像树形dp一样直接dfs出每个结点的信息相加。
比如1->2, 1->3, 2->3,像这个例子,从1出发访问3个点,2出发2个,3出发1个。
如果结点1把2和3的信息简单相加,再算上它本身,得到的结果就是4。
我们会发现我们要维护的就是一个集合,每个结点的信息应该是它后续点的信息的并集。
用状态压缩的思想,点虽然达到5000,分组就行。我是30位为一组,一共分170组,集合每次并的操作的复杂度是常数170。
同时用记忆化搜索的话,每个点访问一次,总复杂度O(N),常数大一点没关系。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<sstream>
#include<vector>
#include<string>
using namespace std;
const int N = 5001;
inline void get(int num, int &x, int &y){
num--;
x = num/30;
y = num%30;
}
struct Bit{
int x[170];
Bit(){
memset(x,0,sizeof(x));
}
void set(int num){
memset(x,0,sizeof(x));
if(num){
int a,b;
get(num, a, b);
x[a]|=(1<<b);
}
}
inline int number(int a){
int res = 0;
for(; a; a^=(a&(-a))) res++;
return res;
}
int count(){
int res = 0;
for(int i=0; i<170; i++) res += number(x[i]);
return res;
}
void OR(Bit &A){
for(int i=0; i<170; i++) x[i]|=A.x[i];
}
};
vector<int> V[N];
Bit b[N];
bool vis[N];
int a[N];
void dfs(int x){
if(vis[x]) return;
for(int i=0; i<V[x].size(); i++){
int j=V[x][i];
dfs(j);
b[x].OR(b[j]);
}
vis[x]=1;
}
int main(){
ios::sync_with_stdio(false);
int n,m;
while(cin >> n >> m){
for(int i=1; i<=n; i++){
V[i].clear();
b[i].set(i);
vis[i]=0;
}
for(int i=0; i<m; i++) cin >> a[i];
string s;
getline(cin, s);
int x, y;
for(int i=0; i<n; i++){
getline(cin, s);
stringstream ss(s);
ss >> x;
while(ss >> y){
V[x].push_back(y);
}
}
int ans=-1, id;
for(int i=0; i<m; i++){
dfs(a[i]);
int cur = b[a[i]].count();
if(cur>ans || (cur==ans&&a[i]<id)){
id = a[i];
ans = cur;
}
}
printf("%d\n", id);
}
return 0;
}