您的位置:首页 > 其它

BZOJ 1093: [ZJOI2007]最大半连通子图

2014-09-01 10:40 218 查看
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1093

首先我们将原图求强连通然后缩点,显然我们在一个强连通里面所有的点都取,然后要在缩点后的图中取一条权值和最大的链,直接dp就行了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <string.h>
#include <queue>
#include <vector>
#include <algorithm>
#include <cassert>
#include <set>
#include <map>
#include <cmath>
#include <ctime>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<(b);++i)
#define rrep(i,a,b) for(int i=(a);i>=(b);--i)
#define clr(a,x) memset(a,(x),sizeof(a))
#define eps 1e-8
#define LL long long
#define mp make_pair
const int maxn=100000+5;
struct Node
{
int v;
Node * next;
}*first[maxn],edges[maxn*20];
int ptr;
vector<int> adj[maxn];
void add(int u,int v)
{
edges[++ptr].v=v;
edges[ptr].next=first[u];
first[u]=&edges[ptr];
}
int n,m,mod;

void input()
{
ptr=0; clr(first,0);
while(m--) {
int u,v; scanf("%d%d",&u,&v);
add(u,v);
}
}

int sccno[maxn],low[maxn],scc_cnt,dfn,pre[maxn];
vector<int> scc[maxn];
stack<int> S;
inline int min(int a,int b) { return a<b?a:b; }
inline int max(int a,int b) { return a>b?a:b; }

int dfs(int u)
{
pre[u]=low[u]=++dfn;
S.push(u);
for(Node*p=first[u];p;p=p->next) {
int v=p->v;
if(!pre[v]) low[u]=min(low[u],dfs(v));
else if(!sccno[v]) low[u]=min(low[u],pre[v]);
}
if(low[u]==pre[u]) {
scc[++scc_cnt].clear();
for(;;) {
int x=S.top(); S.pop();
sccno[x]=scc_cnt;
scc[scc_cnt].push_back(x);
if(x==u) break;
}
}
return low[u];
}

void find_scc()
{
clr(sccno,0); clr(pre,0); clr(low,0);
dfn=scc_cnt=0;
rep(i,1,n+1) if(!pre[i]) dfs(i);
}

int ind[maxn],q[maxn],front,rear;
int value[maxn];
bool vis[maxn];
void build()
{
clr(vis,0); clr(ind,0);
rep(i,1,scc_cnt+1) {
vis[i]=true;
S.push(i);
adj[i].clear(); value[i]=scc[i].size();
rep(j,0,scc[i].size()) {
int u=scc[i][j];
for(Node * p=first[u];p;p=p->next) {
int v=p->v;
if(!vis[sccno[v]]) { ++ind[sccno[v]]; adj[sccno[u]].push_back(sccno[v]); S.push(sccno[v]); }
vis[sccno[v]]=true;
}
}
while(S.size()) { vis[S.top()]=false; S.pop(); }
}
}

LL sum[maxn],dp[maxn];
void solve()
{
find_scc();
build();
front=rear=0;
n=scc_cnt;
rep(i,1,n+1)
if(ind[i]==0) q[rear++]=i;
while(front<rear) {
int u=q[front++];
rep(i,0,adj[u].size()) {
int v=adj[u][i];
if(--ind[v]==0) q[rear++]=v;
}
}
clr(sum,0); clr(dp,0);
rrep(i,rear-1,0) {
int u=q[i]; dp[u]=value[u];
if(adj[u].size()==0) {
sum[u]=1;
continue;
}
LL num=0,maxsize=0;
rep(j,0,adj[u].size()) {
int v=adj[u][j];
if(maxsize<dp[v]) {
maxsize=dp[v];
num=sum[v];
} else if(maxsize==dp[v]) num=(num+sum[v])%mod;
}
dp[u] += maxsize;
sum[u] = num;
}
LL num=0,maxsize=0;
rep(i,1,n+1)
if(dp[i]>maxsize)
{
maxsize=dp[i];
num=sum[i];
} else if(dp[i]==maxsize) {
num+=sum[i];
num%=mod;
}
printf("%lld\n%lld\n",maxsize,num);
}

int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%d%d%d",&n,&m,&mod)==3) {
input();
solve();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: