<tarjan||拓扑>codevs 2066 三角恋

来源:互联网 发布:淘宝卖什么比较冷门 编辑:程序博客网 时间:2024/05/17 07:22

去题面的传送门
第一次做超时了,只得了四十分。
做法是dfs找大小为3的环。数据范围是2000,一定超时。
下面是40分的代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=2000+10;int cnt,t,n;int nxt[maxn*maxn],fist[maxn];bool flg,bo;bool vis[maxn][maxn],used[maxn];struct hh{    int f,t;}e[maxn*maxn];void build(int f,int t){    e[++cnt]=(hh){f,t};    nxt[cnt]=fist[f];    fist[f]=cnt;}void init(){    cnt=flg=0;    memset(fist,-1,sizeof(fist));    memset(nxt,0,sizeof(nxt));    memset(e,0,sizeof(e));    memset(vis,0,sizeof(vis));    memset(used,0,sizeof(used));}bool dfs(int x,int k){    for(int i=fist[x];i!=-1;i=nxt[i])    {        int v=e[i].t;        if(k>3&&vis[v][k+1-3])         {            bo=1;            return true;         }        vis[v][k+1]=true;        used[v]=true;        dfs(v,k+1);        if(bo) return true;        vis[v][k+1]=false;    }    vis[x][k]=false;    if(!bo) return false;    else return true;}int main(){    scanf("%d",&t);    while(t--)    {        init();        scanf("%d",&n);        for(int i=1;i<=n;++i)        {            string s;            cin>>s;             for(int j=0;j<n;++j)              if(s[j]=='1') build(i,j+1);        }         for(int i=1;i<=n;++i)          if(!used[i])          {            used[i]=true;            vis[i][1]=true;            bo=0;            if(dfs(i,1))             {                flg=1;                break;            }          }        if(flg) printf("Yes\n");        else printf("No\n");    }    return 0;} 

我又尝试先把不可能构成环的节点删除,也就是拓扑找入度为0的点,然后再进行dfs。但是这样仍然超时,代码是这样:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int maxn=2000+10;int cnt,t,n;int nxt[maxn*maxn],fist[maxn],ru[maxn];bool flg,bo;bool used[maxn];struct hh{    int f,t;}e[maxn*maxn];queue<int>q;void build(int f,int t){    e[++cnt]=(hh){f,t};    nxt[cnt]=fist[f];    fist[f]=cnt;}void init(){    cnt=flg=0;    memset(ru,0,sizeof(ru));    memset(fist,-1,sizeof(fist));    memset(nxt,0,sizeof(nxt));    memset(e,0,sizeof(e));    memset(used,0,sizeof(used));    while(!q.empty()) q.pop();}bool dfs(int x,int k,int num){    for(int i=fist[x];i!=-1;i=nxt[i])    {        int v=e[i].t;        if(k==3&&v==num)        {            bo=1;            return true;        }        if(used[v]) continue;        if(k<4) dfs(v,k+1,num);        if(bo) return true;    }    if(bo) return true;    else return false;}void topu(){    for(int i=1;i<=n;++i)      if(!ru[i])      {         q.push(i);         used[i]=true;      }    while(!q.empty())    {        int u=q.front();        q.pop();        for(int i=fist[u];i!=-1;i=nxt[i])        {            int v=e[i].t;            if(ru[v]) ru[v]--;            else            {                used[v]=true;                q.push(v);            }        }    }}int main(){    scanf("%d",&t);    while(t--)    {        init();        scanf("%d",&n);        for(int i=1;i<=n;++i)        {            char s[maxn];            scanf("%s",s);             for(int j=0;j<n;++j)              if(s[j]=='1')               {                  ru[j+1]++;                  build(i,j+1);              }        }         topu();        for(int i=1;i<=n;++i)          if(!used[i])          {            used[i]=true;            bo=0;            if(dfs(i,1,i))             {                flg=1;                break;            }          }        if(flg) printf("Yes\n");        else printf("No\n");    }    return 0;} 

这时候我就懵了
百度题解是找环,能找到环就是存在三角恋(wtf??)
应该是理解错题面了,不一定非得是三个人??
那就上拓扑找环的代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int maxn=2000+10;int t,n,cnt,ans;int fist[maxn],nxt[maxn*maxn],ru[maxn];struct hh{    int f,t;}e[maxn*maxn];queue<int>q;void build(int f,int t){    e[++cnt]=(hh){f,t};    nxt[cnt]=fist[f];    fist[f]=cnt;}void init(){    cnt=ans=0;    memset(e,0,sizeof(e));    memset(ru,0,sizeof(ru));    memset(fist,-1,sizeof(fist));    memset(nxt,0,sizeof(nxt));    while(!q.empty()) q.pop();}void topu(){    for(int i=1;i<=n;++i)       if(!ru[i])       {        ans++;        q.push(i);      }    while(!q.empty())    {        int u=q.front();        q.pop();        for(int i=fist[u];i!=-1;i=nxt[i])        {            int v=e[i].t;            if(ru[v]) ru[v]--;            if(!ru[v])             {                ans++;                q.push(v);            }        }    }}int main(){    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        init();        for(int i=1;i<=n;++i)        {            string s;            cin>>s;            for(int j=0;j<n;++j)              if(s[j]=='1')               {                ru[j+1]++;                build(i,j+1);              }        }        topu();        if(ans==n) printf("No\n");        else printf("Yes\n");    }    return 0;}

然后是tarjan做法

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<stack>using namespace std;const int maxn=2000+10;int n,t,cnt,scc_cnt,Index;int fist[maxn],nxt[maxn*maxn],dfn[maxn],low[maxn],scc[maxn];bool flg;struct hh{    int f,t;}e[maxn*maxn];stack<int>s;void init(){    cnt=flg=0;    memset(fist,-1,sizeof(fist));    memset(nxt,0,sizeof(nxt));    memset(e,0,sizeof(e));    memset(dfn,0,sizeof(dfn));    memset(low,0,sizeof(low));    memset(scc,0,sizeof(scc));    while(!s.empty()) s.pop();}void build(int f,int t){    e[++cnt]=(hh){f,t};    nxt[cnt]=fist[f];    fist[f]=cnt;}void tarjan(int i){    if(flg) return;    dfn[i]=low[i]=++Index;    s.push(i);    for(int j=fist[i];j!=-1;j=nxt[j])    {        int v=e[j].t;        if(!dfn[v])        {            tarjan(v);            low[i]=min(low[i],low[v]);        }        else if(!scc[v]) low[i]=min(low[i],dfn[v]);    }    if(low[i]==dfn[i])    {        scc_cnt++;        int j,tot=0;        do        {            j=s.top();            s.pop();            tot++;            scc[j]=scc_cnt;        }        while(i!=j);         if(tot>1)        {            flg=1;            return ;        }    }}int main(){    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        init();        for(int i=1;i<=n;++i)        {            string s;            cin>>s;            for(int j=0;j<n;++j)              if(s[j]=='1') build(i,j+1);        }        for(int i=1;i<=n;++i)          if(!scc[i])            tarjan(i);        if(flg) printf("Yes\n");        else printf("No\n");    }    return 0;} 
原创粉丝点击