POJ上面这个题的时限是15000ms,看着都DT,最起码挺吓人的……
题意是,N个男生和N个女生,告诉你每个男生喜欢的女生编号,然后给出一个初始匹配(这个初始匹配是完备匹配),然后求所有可能的完备匹配,按升序输出。当然,如果暴整的话(当然我没试过),2000个男生+2000个女生,最多有20W条有向边,会很销魂吧应该……
看了一个神牛的报告,把这个转化成强连通问题:
首先按照给出的有向边建图,然后根据最后的那个完备匹配在图中加入反向边(就是根据那个完备匹配连 女生 到 男生 的边),那么在这个图中,属于同一个强连通的点对一定是合法点对。把他们排序输出即可。
我开始用的是优先队列,自以为会很快,跑了3800+ms,换成sort,是3400ms+,下面是代码:
#include<cstdio> #include<cstring> #include<stack> #include<queue> #include<algorithm> using namespace std; const int N = 4010; struct node{ int val; bool operator < (const node &a) const{ return a.val<val; } }; struct Edge{ int s,e,next; }edge[300010]; int n,e_num,vis_num,cnt; int head[N],tim[N],low[N],instack[N],belong[N]; void AddEdge(int a,int b){ edge[e_num].s=a; edge[e_num].e=b; edge[e_num].next=head[a]; head[a]=e_num++; } void getmap(){ int i,j,m,x; e_num=0; memset(head,-1,sizeof(head)); for(i=1;i<=n;i++){ scanf("%d",&m); for(j=1;j<=m;j++){ scanf("%d",&x); AddEdge(i,n+x); } } for(i=1;i<=n;i++) { scanf("%d",&x); AddEdge(n+x,i); } } stack <int> st; void tarjan(int x){ int i,j; tim[x]=low[x]=++vis_num; st.push(x); instack[x]=1; for(i=head[x];i!=-1;i=edge[i].next){ int u=edge[i].e; if(tim[u]==-1){ tarjan(u); if(low[u]<low[x])low[x]=low[u]; } else if(instack[u] && tim[u]<low[x]) low[x]=tim[u]; } if(tim[x]==low[x]){ cnt++; do{ j=st.top(); st.pop(); instack[j]=0; belong[j]=cnt; }while(j!=x); } } /*用sort排序的话,会更快 void out(int A[], int len) { sort(A+1, A+1+len); printf("%d ", len); for(int j=1; j<len; ++j) printf("%d ", A[j]); printf("%d\n", A[len]); } */ void solve(){ int i,j,A[N]; cnt=vis_num=0; memset(tim,-1,sizeof(tim)); memset(low,0,sizeof(low)); memset(instack,0,sizeof(instack)); for(i=1;i<=2*n;i++){ if(tim[i]==-1)tarjan(i); } node cur; priority_queue <node> q; for(i=1;i<=n;i++){ int num=0; for(j=head[i];j!=-1;j=edge[j].next){ int u=edge[j].e; if(belong[u]==belong[i]){ cur.val=u-n; q.push(cur); num++; } } printf("%d",num); while(!q.empty()){ node v=q.top(); q.pop(); printf(" %d",v.val); } puts(""); } /*用sort的代码 for(i=1;i<=n;i++){//遍历图中的边,如果起点终点在同一个连通分量,那么就是合法点对 int num=0; for(j=head[i];j!=-1;j=edge[j].next){ int u=edge[j].e; if(belong[i]==belong[u]){ A[++num]=u-n; } } out(A,num); } */ //puts("");这里需要注意,ZOJ的输出比POJ多要求了一个空行 } int main() { while(~scanf("%d",&n)) { getmap(); solve(); } return 0; }