概述
题目链接:http://codeforces.com/gym/100502/attachments。
题意:有n个人旅游,第i个人去的前提是第a[i]个人去,车上最多载k人,最多可以多少人去旅游。
思路:先跑tarjan把强连通块弄出来,然后在树上背包也就是树形dp,具体转移方法比较复杂,看代码吧:
#include<iostream>
#include<cmath>
#include<queue>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<string>
#include<utility>
#include<map>
#include<vector>
#define maxn 200005
#define E 1005
#define V 1005
#define inf 0x3f3f3f3f
using namespace std;
typedef long long LL;
const double eps = 1e-8;
struct edge
{
int to, next;
}Edge[E];
int head[V], e, n;
int indeg[V]; //联通块的入度和出度数
int belong[V], low[V], dfn[V], scc, cnt, num[V], connect[V][V];//dfn[]:遍历到u点的时间; low[]:u点可到达的各点中最小的dfn[v];belong[]:该点所属的联通块;scc:联通块个数;
int S[V], top;//S[]//数组栈
bool vis[V];//v是否在栈中
int dp[V][V], k;
vector<int>p[V];
int addedge(int u, int v)
{
Edge[e].to = v;
Edge[e].next = head[u];
head[u] = e++;
return 0;
}
void tarjan(int u)
{
int v;
dfn[u] = low[u] = ++cnt;//开始时dfn[u] == low[u]
S[top++] = u;//不管三七二十一进栈
vis[u] = true;
for (int i = head[u]; i != -1; i = Edge[i].next)
{
v = Edge[i].to;
if (dfn[v] == 0)//如果v点还未遍历
{
tarjan(v);//向下遍历
low[u] = low[u] < low[v] ? low[u] : low[v];//确保low[u]最小
}
else if (vis[v] && low[u] > dfn[v])//v在栈中,修改low[u]
low[u] = dfn[v];
}
if (dfn[u] == low[u])//u为该强连通分量中遍历所成树的根
{
++scc;
do
{
v = S[--top];//栈中所有到u的点都属于该强连通分量,退栈
vis[v] = false;
belong[v] = scc;
num[scc]++;
} while (u != v);
}
}
int solve()
{
for (int u = 1; u <= n; ++u)
if (!dfn[u])
tarjan(u);
return scc;
}
void dfs(int now){
dp[now][0] = dp[now][num[now]] = 1;
for (int i = 0; i < p[now].size(); i++){
dfs(p[now][i]);
for (int j = k; j > num[now]; j--){
if (dp[now][j])
continue;
for (int l = 0; l <= j - num[now]; l++){
if (dp[now][j - l] && dp[p[now][i]][l]){
dp[now][j] = 1;
}
}
}
}
}
int main(){
memset(head, -1, sizeof(head));
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++){
int u;
scanf("%d", &u);
addedge(u, i);
}
solve();
for (int i = 1; i <= n; i++){
for (int j = head[i]; ~j; j = Edge[j].next){
if (belong[i] == belong[Edge[j].to]||connect[belong[i]][belong[Edge[j].to]])
continue;
connect[belong[i]][belong[Edge[j].to]] = 1;
p[belong[i]].push_back(belong[Edge[j].to]);
indeg[belong[Edge[j].to]]++;
}
}
for (int i = 1; i <= scc; i++){
if (!indeg[i])
p[0].push_back(i);
}
dfs(0);
for (int i = k; i >= 0; i--){
if (dp[0][i]){
printf("%dn", i);
break;
}
}
}
最后
以上就是害怕老师为你收集整理的Gym - 100502 G - Outing的全部内容,希望文章能够帮你解决Gym - 100502 G - Outing所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复