Light OJ 1406 Assassin`s Creed 状态压缩DP+强连通缩点+最小路径覆盖

题目来源:Light OJ 1406 Assassin`s Creed

题意:有向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方

思路:最少的的人能够走全然图 明显是最小路径覆盖问题 这里可能有环 所以要缩点 可是看例子又发现 一个强连通分量可能要拆分 n最大才15 所以就状态压缩

将全图分成一个个子状态 每一个子状态缩点 求最小路径覆盖 这样就攻克了一个强连通分量拆分的问题 最后状态压缩DP求解最优值

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <stack>
using namespace std;
const int maxn = 16;
vector <int> G[maxn], G2[maxn];
int dp[1<<maxn];
int pre[maxn], low[maxn], sccno[maxn];
int clock, scc_cnt;
int n, m;
stack <int> S;
int a[maxn][maxn];
int b[maxn][maxn];

void dfs(int u, int x)
{
	pre[u] = low[u] = ++clock;
	S.push(u);
	for(int i = 0; i < G[u].size(); i++)
	{
		int v = G[u][i];
		if(!(x&(1<<v)))
			continue;
		if(!pre[v])
		{
			dfs(v, x);
			low[u] = min(low[u], low[v]);
		}
		else if(!sccno[v])
		{
			low[u] = min(low[u], pre[v]);
		}
	}
	if(pre[u] == low[u])
	{
		scc_cnt++;
		while(1)
		{
			int x = S.top(); S.pop();
			sccno[x] = scc_cnt;
			if(x == u)
				break;
		}
	}
}
int find_scc(int x)
{
	memset(sccno, 0, sizeof(sccno));
	memset(pre, 0, sizeof(pre));
	scc_cnt = 0, clock = 0;
	for(int i = 0; i < n; i++)
	{
		if(x&(1<<i) && !pre[i])
			dfs(i, x);
	}
	return scc_cnt;
}

int y[maxn];
bool vis[maxn];

bool xyl(int u)
{
	for(int i = 0; i < G2[u].size(); i++)
	{
		int v = G2[u][i];
		if(vis[v])
			continue;
		vis[v] = true;
		if(y[v] == -1 || xyl(y[v]))
		{
			y[v] = u;
			return true;
		}
	}
	return false;
}
int match()
{
	int ans = 0;
	memset(y, -1, sizeof(y));
	for(int i = 1; i <= scc_cnt; i++)
	{
		memset(vis, false, sizeof(vis));
		if(xyl(i))
			ans++;
	}
	return scc_cnt-ans;
}
int main()
{
	int cas = 1;
	int T;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d %d", &n, &m);
		for(int i = 0; i < n; i++)
			G[i].clear();
		memset(a, 0, sizeof(a));
		while(m--)
		{
			int u, v;
			scanf("%d %d", &u, &v);
			u--;
			v--;
			G[u].push_back(v);
			a[u][v] = 1;
		}
		dp[0] = 0;
		//puts("sdf");
		for(int i = 1; i < (1<<n); i++)
		{
			//memset(b, 0, sizeof(b));
			find_scc(i);
			for(int j = 0; j <= n; j++)
				G2[j].clear();
			for(int j = 0; j < n; j++)
				for(int k = 0; k < n; k++)
					if(a[j][k] && sccno[j] && sccno[k] && sccno[j] != sccno[k])
						G2[sccno[j]].push_back(sccno[k]);
				dp[i] = match();
		}
		//puts("sdf");
		for(int s = 1; s < (1<<n); s++)
		{
			for(int i = s; i; i = s&(i-1))
			{
				dp[s] = min(dp[s], dp[s^i] + dp[i]);
			}
		}
		printf("Case %d: %d\n", cas++, dp[(1<<n)-1]);
	}
	return 0;
}
时间: 2024-10-12 15:11:23

Light OJ 1406 Assassin`s Creed 状态压缩DP+强连通缩点+最小路径覆盖的相关文章

Light OJ 1429 Assassin`s Creed (II) BFS+缩点+最小路径覆盖

题目来源:Light OJ 1429 Assassin`s Creed (II) 题意:最少几个人走完全图 可以重复走 有向图 思路:如果是DAG图并且每个点不能重复走 那么就是裸的最小路径覆盖 现在不是DAG 可能有环 并且每个点可能重复走 对于有环 可以缩点 缩点之后的图是DAG图 另外点可以重复走和POJ 2594一样 先预处理连通性 #include <cstdio> #include <cstring> #include <vector> #include &

【上海交大oj】邮递员小F(状态压缩dp)(旅行商问题)

1088. 邮递员小F Description 因为制造类专业很难在大城市立足,曾经立志振兴中华之工业的小F,果断在本科毕业后转行做了一名光荣的邮递员. 他的任务是每天从总局出发,行走于所管辖区域的若干的邮局,收集所有的信,然后再汇总返回总局. 因为工作繁忙,同一个邮局他每天只希望去一次. 来往于任意两个邮局是有一定代价的.而且为了方便统计,假定来回两条道路上的代价假设是一样的. 现在小F希望你能给出他每天的最优行走方案,使得总的代价最少. Input Format 输入数据包括两部分. 第一行

Light OJ 1316 A Wedding Party 最短路+状态压缩DP

题目来源:Light OJ 1316 1316 - A Wedding Party 题意:和HDU 4284 差不多 有一些商店 从起点到终点在走过尽量多商店的情况下求最短路 思路:首先预处理每两点之前的最短路 然后只考虑那些商店 个数小于15嘛 就是TSP问题 状态压缩DP搞一下 状态压缩姿势不对 有必要加强 #include <cstdio> #include <algorithm> #include <queue> #include <vector>

Bear and Floodlight 状态压缩DP啊

Bear and Floodlight Time Limit: 4000MS   Memory Limit: 262144KB   64bit IO Format: %I64d & %I64u [Submit]   [Go Back]   [Status] Description One day a bear lived on the Oxy axis. He was afraid of the dark, so he couldn't move at night along the plane

POJ 3254 Corn Fields 状态压缩DP (C++/Java)

http://poj.org/problem?id=3254 题目大意: 一个农民有n行m列的地方,每个格子用1代表可以种草地,而0不可以.放牛只能在有草地的,但是相邻的草地不能同时放牛, 问总共有多少种方法. 思路: 状态压缩的DP. 可以用二进制数字来表示放牧情况并判断该状态是否满足条件. 这题的限制条件有两个: 1.草地限制. 2.相邻限制. 对于草地限制,因为输入的时候1是可以种草地的. 以"11110"草地分析,就只有最后一个是不可以种草的.取反后得00001  .(为啥取反

HDU1565(状态压缩dp)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8170    Accepted Submission(s): 3095 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数

HDU 3001【状态压缩DP】

题意: 给n个点m条无向边. 要求每个点最多走两次,要访问所有的点给出要求路线中边的权值总和最小. 思路: 三进制状态压缩DP,0代表走了0次,1,2类推. 第一次弄三进制状态压缩DP,感觉重点是对数据的预处理,利用数组分解各个位数,从而达到类似二进制的目的. 然后就是状态的表示,dp[s][i]表示状态s时到达i的最优值. 状态转移也一目了然,不废话. #include<stdio.h> #include<string.h> #include<algorithm> u

Victor and World(spfa+状态压缩dp)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5418 Victor and World Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Others)Total Submission(s): 958    Accepted Submission(s): 431 Problem Description After trying hard fo

poj 3311 Hie with the Pie(状态压缩dp)

Description The Pizazz Pizzeria prides itself in delivering pizzas to its customers as fast as possible. Unfortunately, due to cutbacks, they can afford to hire only one driver to do the deliveries. He will wait for 1 or more (up to 10) orders to be