大致题意:
给出一个有向图的传递闭包矩阵,求出这个图至少有多少条边。
大致思路:
对这个图先用Tarjan缩点,再对缩点后的图求一遍floyd求出至少需要多少条边。
#include<iostream> #include<cstdio> #include <algorithm> #include<cstring> using namespace std; const int inf=1<<30; const int nMax=30015; const int mMax=500100; class edge{ public: int u,v,nex; };edge e[mMax]; int k,head[nMax];//head[i]是以点i为起点的链表头部 void addedge(int a,int b){//向图中加边的算法,注意加上的是有向边//b为a的后续节点既是a---->b e[k].u=a; e[k].v=b; e[k].nex=head[a]; head[a]=k;k++; } int dfn[nMax],low[nMax],sta[nMax],top,atype,belon[nMax],dep,num[nMax]; //atype 强连通分量的个数 bool insta[nMax]; void Tarjan(int u){ //我的Tarjan模版 int i,j; dfn[u]=low[u]=++dep; sta[++top]=u; insta[u]=1; for(i=head[u];i;i=e[i].nex){ int v=e[i].v; if(!dfn[v]){ Tarjan(v); low[u]=min(low[u],low[v]); } else{ if(insta[v])low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]){ atype++; //强连通分量个数 do{ num[atype]++; j=sta[top--]; belon[j]=atype; //第j个点属于第type个连通块 insta[j]=0; }while(u!=j); } } void init(){ k=1; dep=1; top=atype=0; memset(insta,0,sizeof(insta)); //是否在栈中 memset(head,0,sizeof(head)); //静态链表头指针 memset(low,0,sizeof(low)); //Tarjan的low数组 memset(dfn,0,sizeof(dfn)); //Tarjan的dfn数组 memset(belon,0,sizeof(belon)); //记录每个点属于哪一个强连通分量 memset(num,0,sizeof(num)); } int map[300][300]; int main(){ int n,m,i,j,a,b,c,ans; while(cin>>n){ memset(map,0,sizeof(map)); ans=0; init(); for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ cin>>a; if(i!=j&&a){ addedge(i,j); } } } for(i=1;i<=n;i++){ if(!dfn[i]){ Tarjan(i); } } for(i=1;i<k;i++){ if(belon[e[i].u]!=belon[e[i].v]){ map[belon[e[i].u]][belon[e[i].v]]=1; } } for(i=1;i<=atype;i++){ if(num[i]!=1){ ans+=num[i]; } } // for(i=1;i<=atype;i++) // { // for(j=1;j<=atype;j++) // { // if(map[i][j])ans++; // } // } for(k=1;k<=atype;k++){ for(i=1;i<=atype;i++){ for(j=1;j<=atype;j++){ if(map[i][k]&&map[k][j]&&map[i][j]){ map[i][j]=0; //ans--; } } } } for(i=1;i<=atype;i++){ for(j=1;j<=atype;j++){ if(map[i][j])ans++; } } cout<<ans<<endl; } return 0; }