先问你是否能将学生分成两组,每组里面的人互相不认识,我用的2-SAT判断,对于每对认识的人i和j,i&&j=0 可推导i->~j, j->~i, ~i->j, ~j->i 然后没有矛盾的话直接求一个二分图最大匹配就行了 代码: #include<iostream> #include<cstdio> #include<memory.h> #include<stack> using namespace std; const int MAX=405; struct node { int v,next; }g[MAX*100]; int adj[MAX],low[MAX],dfn[MAX],bel[MAX],match[MAX],vis[MAX],map[MAX][MAX]; int inStack[MAX]; int n,m,e,cnt,index; void add(int u,int v) { g[e].v=v; g[e].next=adj[u]; adj[u]=e++; } stack<int>s; int min(int a,int b) { return a<b?a:b; } void tarjan(int u) { int i,v; dfn[u]=low[u]=++index; s.push(u); inStack[u]=1; for(i=adj[u];i!=-1;i=g[i].next) { v=g[i].v; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(inStack[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { cnt++; do { v=s.top(); s.pop(); inStack[v]=0; bel[v]=cnt; }while(u!=v); } } int dfs(int u) { for(int v=1;v<=n;v++) { if(map[u][v]&&!vis[v]) { vis[v]=1; if(match[v]==-1||dfs(match[v])) { match[v]=u; return 1; } } } return 0; } int hungary() { int i,num=0; for(i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(dfs(i)) num++; } return num; } int main() { int i,j; while(scanf("%d%d",&n,&m)!=EOF) { memset(adj,-1,sizeof(adj)); memset(dfn,0,sizeof(dfn)); memset(match,-1,sizeof(match)); memset(map,0,sizeof(map)); memset(inStack,0,sizeof(inStack)); e=cnt=index=0; while(m--) { scanf("%d%d",&i,&j); map[i][j]=1; add(i,j+n); add(j,i+n); add(i+n,j); add(j+n,i); } for(i=1;i<=n*2;i++) { if(!dfn[i]) tarjan(i); } for(i=1;i<=n;i++) { if(bel[i]==bel[i+n]) break; //cout<<bel[i]<<" "<<bel[i+n]<<endl; } if(i>n) cout<<hungary()<<endl; else puts("No"); } return 0; }