UVALive 6432 —— Influence(记忆化搜索 + 状态压缩)

题目: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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值