去题面的传送门
第一次做超时了,只得了四十分。
做法是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;
}