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 <queue>
#include <stack>
using namespace std;
const int maxn = 1010;

int vis[maxn];
int y[maxn];
vector <int> G[maxn], G2[maxn], G3[maxn];
int n, m;
int a[maxn][maxn];

int pre[maxn];
int low[maxn];
int sccno[maxn];
int dfs_clock;
int scc_cnt;
stack <int> S;

void dfs(int u)
{
	pre[u] = low[u] = ++dfs_clock;
	S.push(u);
	for(int i = 0; i < G[u].size(); i++)
	{
		int v = G[u][i];
		if(!pre[v])
		{
			dfs(v);
			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;
		}
	}
}
void find_scc()
{
	dfs_clock = scc_cnt = 0;
	memset(sccno, 0, sizeof(sccno));
	memset(pre, 0, sizeof(pre));
	for(int i = 1; i <= n; i++)
		if(!pre[i])
			dfs(i);
}

void BFS(int u)
{
	queue <int> Q;
	memset(vis, 0, sizeof(vis));
	vis[u] = true;
	Q.push(u);
	while(!Q.empty())
	{
		int x = Q.front(); Q.pop();
		for(int i = 0; i < G2[x].size(); i++)
		{
			int v = G2[x][i];
			if(vis[v])
				continue;
			vis[v] = true;
			G[u].push_back(v);
			Q.push(v);
		}
	}
}
bool dfs2(int u)
{
    for(int i = 0; i < G3[u].size(); i++)
    {
        int v = G3[u][i];
        if(vis[v])
            continue;
        vis[v] = true;
        if(y[v] == -1 || dfs2(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, 0, sizeof(vis));
		if(dfs2(i))
		    ans++;
    }
    return 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(), G2[i].clear(), G3[i].clear();
		while(m--)
		{
			int u, v;
			scanf("%d %d", &u, &v);
			G2[u].push_back(v);
		}
		for(int i = 1; i <= n; i++)
			BFS(i);
		find_scc();

		for(int u = 1; u <= n; u++)
		{
			for(int i = 0; i < G[u].size(); i++)
			{
				int v = G[u][i];
				if(sccno[u] != sccno[v])
					G3[sccno[u]].push_back(sccno[v]);
			}
		}
		printf("Case %d: %d\n", cas++, scc_cnt-match());
	}
    return 0;
}

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

时间: 2024-10-14 22:46:37

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

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

题目来源:Light OJ 1406 Assassin`s Creed 题意:有向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方 思路:最少的的人能够走全然图 明显是最小路径覆盖问题 这里可能有环 所以要缩点 可是看例子又发现 一个强连通分量可能要拆分 n最大才15 所以就状态压缩 将全图分成一个个子状态 每一个子状态缩点 求最小路径覆盖 这样就攻克了一个强连通分量拆分的问题 最后状态压缩DP求解最优值 #include <cstdio> #include <cstri

exam1802 Bounty Hunter II(DAG的最小路径覆盖)

原文:http://www.cnblogs.com/jackiesteed/articles/2043934.html DAG的最小路径覆盖是指找最小数目的互相不相交的有向路径,满足DAG的所有顶点都被覆盖. 首先给出公式:DAG的最小路径覆盖数=DAG图中的节点数-相应二分图中的最大匹配数. 那么对应一个DAG,如何构造相应的二分图?对于DAG中的一个顶点p,二分图中有两个顶点p和p',对应DAG中的一条有向边p->q,二分图中有p-q'的一条无向边.二分图中p属于S集合,p'属于T集合. 下

(最小路径覆盖) News 消息传递 (hust OJ 2604)

http://begin.lydsy.com/JudgeOnline/problem.php?id=2604 Description 总部最近打算向下面的N个工作人员发出了一条秘密消息.因为它是机密,所以只能一对一的传递消息,也就是说每一个人知道消息之后只能把消息传给他能够传达到的且还未知道该消息的若干个人中的一个.对于A.B两个人,可能存在A能够传消息给B,而B无法传消息给A的情况.现在总部为了防止消息被泄露,命令你计算最开始总部至少要告诉多少人消息,才能保证最终所有人都知道了这个消息. In

light oj 1066Gathering Food (bfs 稍微有点小坑)

1066 - Gathering Food Winter is approaching! The weather is getting colder and days are becoming shorter. The animals take different measures to adjust themselves during this season. - Some of them "migrate." This means they travel to other plac

light oj 1236 【大数分解】

给定一个大数,分解质因数,每个质因子的个数为e1,e2,e3,--em, 则结果为((1+2*e1)*(1+2*e2)--(1+2*em)+1)/2. //light oj 1236 大数分解素因子 #include <stdio.h> #include <iostream> #include <string.h> #include <algorithm> #include <math.h> #include <ctype.h> #i

[2016-04-21][light]OJ[1234][Harmonic Number]

时间:2016-04-21 22:18:26 星期四 题目编号:[2016-04-21][light]OJ[1234][Harmonic Number] 题目大意:求∑nk=11kn∈(1,108),精确到10?8求∑k=1n1kn∈(1,108),精确到10?8 分析: 想法是打表,然后输出,但是直接打表会爆内存 解决办法,就是每隔100个来打表,节省1100的空间,然后从那个值开始计算到当前值解决办法,就是每隔100个来打表,节省1100的空间,然后从那个值开始计算到当前值 对应的整百就是n

HDU-2128-Tempter of the Bone II(BFS)

Problem Description The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze was changed and the way he came in was lost.He realized that the bone was a trap, and he tried desperately to get out

Light OJ 1411 Rip Van Winkle`s Code 线段树成段更新

题目来源:Light OJ 1411 Rip Van Winkle`s Code 题意:3中操作 1种查询 求区间和 其中每次可以把一段区间从左到右加上1,2,3,...或者从右到左加上...3,2,1 或者把某个区间的数都置为v 思路:我是加了6个域 add是这段区间每个数都要加上add  add是这么来的 对与123456...这个等差数列 可能要分为2个区间 那么我就分成123和123 两个右边的等差数列每个数还应该加上3 所以右区间add加3 v是这个区间都要置为v 他的优先级最高 b是

Light OJ 1168 Wishing Snake 强连通缩点+哈密顿通路

题目来源:Light OJ 1168 Wishing Snake 题意:有点难看懂题意 看了一个小时再加别人的代码才懂意思 从0开始 输入的那些每一对u v 都要经过 就是从0到到达那些点 思路:首先缩点 每一个强连通分量里面的点都是可达的 缩点后的图是有向无环图 如果从0这个强连通分量可以出去到2个强连通分量 那么这两个强连通分量是不可能相互可达 所以可行的方案就是所有的强连通分量连成一线 一个一个串起来 除了第一个 出度是1入度是0和最后一个出度是0入度是1 其他都是入度等于出度是1 特判只