2017.9.2 最大半联通子图 思考记录

来源:互联网 发布:窗户 知乎 编辑:程序博客网 时间:2024/05/17 23:41

这个题一看上去似乎很难,,   半联通子图根本就没听说过啊

但经过一段时间的思考之后似乎模型挺直接的、

但是其实,他就是问你一个选点最多的路径、 因为如果这些点如果不能能构成一条路径的话,不在路径上的点一定会以一个方向走入这条路径来 会导致相反方向的点不能到达



对于能互达的点,他们发出的任意一条边都可以作为路径,因此tarjan缩点  然后用拓扑序找路径即可

2A(第一遍MLE、)

码:


#include<iostream>#include<cstdio>using namespace std;#include<vector>#include<queue>#include<cstring>vector<int>v[100005];queue<int>q;#define N 1000005int dis,hou[N],xia[N],zhong[N],qi[N],d[N],s[N],sta[N],top,tot,cnt,jh[N],ru[N],f[N][3],pd[N],n,m,x,max1,max2;void jian(int x,int y){++tot;hou[tot]=xia[x];xia[x]=tot;zhong[tot]=y;qi[tot]=x;}void dfs(int o){int i;d[o]=++dis;s[o]=dis;sta[++top]=o;for(i=xia[o];i!=-1;i=hou[i]){int nd=zhong[i];//if(nd==fu)continue;if(d[nd]==0){  dfs(nd);s[o]=min(s[o],s[nd]);}else if(jh[nd]==0)s[o]=min(s[o],s[nd]);}if(s[o]==d[o]){    ++cnt;while(sta[top]!=o){jh[sta[top]]=cnt;v[cnt].push_back(sta[top]);top--;}jh[sta[top]]=cnt;v[cnt].push_back(sta[top]);top--;}}void dp(){int i,j;for(i=1;i<=m;i++){if(jh[qi[i]]!=jh[zhong[i]])ru[jh[zhong[i]]]++;}for(i=1;i<=cnt;i++){if(ru[i]==0)q.push(i);}while(!q.empty()){int st=q.front();f[st][0]+=v[st].size();if(f[st][1]==0)f[st][1]=1;q.pop();for(i=0;i<v[st].size();i++){int st2=v[st][i];for(j=xia[st2];j!=-1;j=hou[j]){int nd=zhong[j];if(jh[nd]==st)continue;ru[jh[nd]]--;    if(pd[jh[nd]]!=st){if(f[jh[nd]][0]<f[st][0]){f[jh[nd]][0]=f[st][0];f[jh[nd]][1]=f[st][1];}else if(f[jh[nd]][0]==f[st][0]){f[jh[nd]][1]+=f[st][1];f[jh[nd]][1]%=x;}pd[jh[nd]]=st;}if(ru[jh[nd]]==0){q.push(jh[nd]);}}}}}int main(){memset(xia,-1,sizeof(xia));int i,a,b;scanf("%d%d%d",&n,&m,&x);for(i=1;i<=m;i++){scanf("%d%d",&a,&b);jian(a,b);ru[b]++;}for(i=1;i<=n;i++)if(jh[i]==0)dfs(i);memset(ru,0,sizeof(ru));dp();for(i=1;i<=cnt;i++){if(max1<f[i][0]){max1=f[i][0];max2=f[i][1];}else if(max1==f[i][0])max2+=f[i][1],max2%=x;}printf("%d\n%d",max1,max2);}






原创粉丝点击