【解析】Hash,离散化,Tarjan
[分析]
对于每个名字,首先离散化成编号。
用hash或者其他,反正不要最基本的就行了,否则O(N^2L)会爆掉。
然后请参考:http://www.cnblogs.com/Randolph87/p/3757817.html
[吐槽]
难得吐槽一下,做这道题竟然做了一个上午,开始暴力求标号,然后一直TLE。
中间map的数据范围少开了N,也试过几次WA。
这不是水题吗,为什么会是一个艰难的Accept...
[小结]
求二分图完备匹配的必要边,①存不存在增广环? O(N^2) ②直接试着删去按照hungery找完备匹配 O(N^3)。
[代码]
#include <cstdio> #include <cstring> #include <cstdlib> using namespace std; typedef unsigned long long ULL; const int N=8002; const int M=20001; const int L=12; const int T=37; const int LMT=100009; int n,m; struct G { int v,nxt; }map[M+N]; int tt,hd[N]; int dfn[N],pre[N],ct; int edge[N][2]; int v[N],color[N],stk[N],cc; char t[L]; struct T { char s[L]; int nxt; }hash[N]; int num,hh[LMT]; inline void ins(int u,int v) { map[++tt].v=v; map[tt].nxt=hd[u]; hd[u]=tt; } void tarjan(int now) { dfn[now]=pre[now]=++ct; stk[++stk[0]]=now,v[now]=1; for (int k=hd[now];k;k=map[k].nxt) { if (v[map[k].v]==2) continue; if (v[map[k].v]==1) { if (pre[map[k].v]<dfn[now]) dfn[now]=pre[map[k].v]; continue; } tarjan(map[k].v); if (dfn[map[k].v]<dfn[now]) dfn[now]=dfn[map[k].v]; } if (pre[now]==dfn[now]) { cc++; for (;stk[stk[0]]!=now;stk[0]--) color[stk[stk[0]]]=cc,v[stk[stk[0]]]=2; color[stk[stk[0]]]=cc; v[stk[stk[0]--]]=2; } } inline ULL h(void) { ULL sum=0; int lt=strlen(t); for (int i=0;i<lt;i++) sum=sum*T+t[i]-'0'; return sum; } int pos(void) { int key=h()%LMT; for (int k=hh[key];k;k=hash[k].nxt) if (!strcmp(hash[k].s,t)) return k; memmove(hash[++num].s,t,sizeof t); hash[num].nxt=hh[key]; return hh[key]=num; } int main(void) { int t1,t2; scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%s",t); t1=pos(); scanf("%s",t); t2=pos(); edge[i][0]=t1,edge[i][1]=t2; ins(t1,t2); } scanf("%d",&m); for (int i=1;i<=m;i++) { scanf("%s",t); t1=pos(); scanf("%s",t); t2=pos(); ins(t2,t1); } for (int i=1;i<=n;i++) if (!v[edge[i][0]]) tarjan(edge[i][0]); for (int i=1;i<=n;i++) printf("%s\n",color[edge[i][0]]==color[edge[i][1]]?"Unsafe":"Safe"); return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-19 05:05:38