算法竞赛入门经典 写题笔记(第五章 图论算法与模型3)

本节内容——

  • 生成树相关问题
  • 二分图最大匹配
  • 二分图最佳完美匹配
  • 稳定婚姻问题

知识点部分

例题20 秦始皇修路

秦朝有n(n<=1000)个城市,需要修建一些道路使得任意两个城市之间都可以联通。道士徐福生成他可以用法术修路,不花钱,也不用劳动力,但只能修一条路,因此需要慎重选择法术修建哪一条路。秦始皇不仅希望其他道路的总长度B尽量短(这样可以节省劳动力),还希望法术连接的两个城市的人口之和A尽量大,因此下令寻找一个A/B最大的方案。

我们可以先建立出最小生成树,然后枚举每条边(u,v),然后删除最小生成树上(u,v)之间的路径上的最大权\(maxcost[u][v]\)

现在的问题就是如何O(n)的求出来在最小生成树上到一个点的路径上的最大值。而这个也不难,一个dfs就完事了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define MAXN 2010
using namespace std;
int n,m,t,T,cnt;
int head[MAXN],fa[MAXN];
double maxx[MAXN][MAXN];
struct Edge{int nxt,to;double dis;}edge[MAXN*MAXN];
struct Node{int x,y,w;}node[MAXN];
struct Line{int u,v;double dis;}line[MAXN*MAXN];
inline void add(int from,int to,double dis)
    {edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis,head[from]=t;}
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline bool cmp(Line x,Line y){return x.dis<y.dis;}
inline double dist(int a,int b)
    {return sqrt((node[a].x-node[b].x)*(node[a].x-node[b].x)+(node[a].y-node[b].y)*(node[a].y-node[b].y));}
inline void init(int now,int x,int pre,double cur_ans)
{
    maxx[now][x]=cur_ans;
    for(int i=head[x];i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(v==pre) continue;
        init(now,v,x,max(cur_ans,edge[i].dis));
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&T);
    while(T--)
    {
        memset(head,0,sizeof(head));
        t=cnt=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=n;i++)
            scanf("%d%d%d",&node[i].x,&node[i].y,&node[i].w);
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                line[++cnt]=(Line){i,j,dist(i,j)};
        sort(&line[1],&line[cnt+1],cmp);
        // for(int i=1;i<=cnt;i++) printf("dis[%d]=%.2lf\n",i,line[i].dis); 
        // cout<<endl;
        int sum=0;
        double all=0.0;
        for(int i=1;i<=cnt;i++)
        {
            int a=find(line[i].u),b=find(line[i].v);
            // printf("u=%d v=%d a=%d b=%d\n",line[i].u,line[i].v,a,b);
            if(a==b) continue;
            fa[a]=b;
            sum++;
            all+=line[i].dis;
            add(line[i].u,line[i].v,line[i].dis),add(line[i].v,line[i].u,line[i].dis);
            if(sum==n-1) break;
        }
        // printf("all=%.2lf\n",all);
        for(int i=1;i<=n;i++) init(i,i,-1,0);
        // for(int i=1;i<=n;i++)
        //     for(int j=i+1;j<=n;j++)
        //         printf("maxx[%d][%d]=%2.lf\n",i,j,maxx[i][j]);
        double ans=0.0;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                ans=max(ans,1.0*(node[i].w+node[j].w)/(all-maxx[i][j]));
        printf("%.2lf\n",ans);
    }
    return 0;
}

例题21 邦德

有n座城市通过m条双向道路相连,每条道路都有一个危险系数。你的任务是回答若干个询问,每个询问包含一个起点s和一个终点t,要求找到一条从s到t的路,使得途径所有边的最大危险系数最小。

求最小瓶颈路。我们还可以按照上面那个题的思想,在dfs的时候更新到一个点的最值。
但是这样子是\(O(n^2)\)的。
看到数据范围想到\(log\)的时间复杂度——数据结构?好像不星啊。那就倍增吧......
挺好写的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define MAXN 100010
using namespace std;
int n,m,t,q,kase;
int head[MAXN],fa[MAXN][20],maxx[MAXN][20],dep[MAXN],ff[MAXN];
struct Edge{int nxt,to,dis;}edge[MAXN<<1];
struct Line{int u,v,w;}line[MAXN<<1];
inline int find(int x){return x==ff[x]?x:ff[x]=find(ff[x]);}
inline bool cmp(struct Line x,struct Line y){return x.w<y.w;}
inline void add(int from,int to,int dis)
{
    edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis,head[from]=t;
    edge[++t].nxt=head[to],edge[t].to=from,edge[t].dis=dis,head[to]=t;
}
inline void dfs(int x,int pre)
{
    dep[x]=dep[pre]+1;
    for(int i=head[x];i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(v==pre) continue;
        maxx[v][0]=edge[i].dis;
        fa[v][0]=x;
        dfs(v,x);
    }
}
inline void init()
{
    for(int j=1;j<=19;j++)
    {
        for(int i=1;i<=n;i++)
        {
            fa[i][j]=fa[fa[i][j-1]][j-1];
            // printf("maxx[%d][%d]=max(%d %d)\n",i,j,maxx[i][j-1],maxx[fa[i][j-1]][j-1]);
            maxx[i][j]=max(maxx[i][j-1],maxx[fa[i][j-1]][j-1]);
        }
    }
    // for(int i=1;i<=n;i++)
    //     for(int j=0;j<=2;j++)
    //         printf("fa[%d][%d]=%d maxx[%d][%d]=%d\n",i,j,fa[i][j],i,j,maxx[i][j]);
}
inline int query(int x,int y)
{
    // printf("x=%d y=%d\n",x,y);
    int cur_ans=0;
    if(dep[x]<dep[y]) swap(x,y);
    int cur=dep[x]-dep[y];
    for(int i=19;i>=0;i--)
        if(cur&(1<<i))
        {
            cur_ans=max(cur_ans,maxx[x][i]),x=fa[x][i];
            // printf("cur_ans=%d x=%d\n",cur_ans,x);
        }
    if(x==y) return cur_ans;
    for(int i=19;i>=0;i--)
    {
        if(fa[x][i]!=fa[y][i])
        {
            cur_ans=max(cur_ans,maxx[x][i]);
            cur_ans=max(cur_ans,maxx[y][i]);
            x=fa[x][i],y=fa[y][i];
        }
    }
    cur_ans=max(cur_ans,maxx[x][0]);
    cur_ans=max(cur_ans,maxx[y][0]);
    return cur_ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    while(scanf("%d%d",&n,&m)==2)
    {
        if(kase==0) kase++;
        else puts("");
        memset(head,0,sizeof(head));
        memset(fa,0,sizeof(fa));
        memset(maxx,0,sizeof(maxx));
        memset(dep,0,sizeof(dep));
        t=0;
        for(int i=1;i<=n;i++) ff[i]=i;
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&line[i].u,&line[i].v,&line[i].w);
        sort(&line[1],&line[m+1],cmp);
        int sum=0;
        for(int i=1;i<=m;i++)
        {
            int a=find(line[i].u),b=find(line[i].v);
            if(a!=b)
            {
                ff[a]=b;
                sum++;
                add(line[i].u,line[i].v,line[i].w);
                if(sum==n-1) break;
            }
        }
        // for(int i=1;i<=n;i++)
        // {
        //     cout<<"i="<<i<<" ";
        //     for(int j=head[i];j;j=edge[j].nxt)
        //         cout<<edge[j].to<<" ";
        //     cout<<endl;
        // }
        dfs(1,0);
        init();
        scanf("%d",&q);
        while(q--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d\n",query(x,y));
        }
    }
    return 0;
}

例题22 比赛网络

你需要花费步超过cost元来搭建一个比赛网络。网络中有n台机器,编号为0~n-1,其中机器0为服务器,其他机器为客户机。一共有m条可以使用的网线,其中第i条网线的发送端是机器\(u_i\),接受端是机器\(v_i\)(数据只能从机器\(u_i\)单向传输到机器\(v_i\)),带宽为\(b_i Kbps\),费用为\(c_i\)元。每台客户机应当恰好从一台机器接受数据(即恰好有一条网线的接受端是该机器),而服务器不应从任何机器接受数据。你的任务是最大化网络中的最小带宽。

嘛.....就是二分带宽+最小有向生成树(最小树形图)判断.......
不会最小树形图的可以去我的学习笔记里面看OI树上问题 简单学习笔记QAQ

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define MAXN 100010
#define INF 0x3f3f3f3f
using namespace std;
int cost,T,ans;
int top[MAXN],id[MAXN],minn[MAXN],fa[MAXN];
struct Edge{int u,v,dis,id,c;}edge[MAXN<<1],pre[MAXN<<1];
inline bool solve(int n,int m,int root)
{
    ans=0;
    while(233)
    {
        int cnt=0;
        for(int i=1;i<=n;i++) id[i]=top[i]=fa[i]=0,minn[i]=INF;
        for(int i=1;i<=m;i++)
        {
            int u=edge[i].u,v=edge[i].v;
            if(u!=v&&edge[i].dis<minn[v])
                fa[v]=u,minn[v]=edge[i].dis; 
        }
        minn[root]=0;
        for(int i=1;i<=n;i++)
        {
            if(minn[i]==INF) return false;
            ans+=minn[i];
            int u;
            for(u=i;u!=root&&top[u]!=i&&!id[u];u=fa[u]) top[u]=i;
            if(u!=root&&!id[u])
            {
                id[u]=++cnt;
                for(int v=fa[u];v!=u;v=fa[v]) id[v]=cnt;
            }
        }
        if(!cnt) return true;
        for(int i=1;i<=n;i++) 
            if(!id[i])
                id[i]=++cnt;
        for(int i=1;i<=m;i++)
        {
            int u=edge[i].u,v=edge[i].v;
            int last=minn[v];
            if((edge[i].u=id[u])!=(edge[i].v=id[v]))
                edge[i].dis-=last;
        }
        n=cnt,root=id[root];
    }
}
inline bool check(int n,int m,int x)
{
    int kkk=0;
    ans=0;
    for(int i=1;i<=m;i++)
        if(pre[i].c>=x) edge[++kkk]=pre[i];
    // printf("x=%d\n",x);
    // for(int i=1;i<=kkk;i++)
    //     printf("%d %d %d %d\n",edge[i].u,edge[i].v,edge[i].c,edge[i].dis);
    if(solve(n,kkk,1)==false) return false;
    // printf("ans=%d\n",ans);
    if(ans<=cost) return true;
    else return false;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&T);
    int m,n;
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&cost);
        // printf("n=%d m=%d cost=%d\n",n,m,cost);
        int l=INF,r=0,ansans=-1;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&pre[i].u,&pre[i].v,&pre[i].c,&pre[i].dis);
            // printf("%d d %d %d\n",pre[i].u,pre[i].v,pre[i].c,pre[i].dis);
            pre[i].u++,pre[i].v++;
            l=min(l,pre[i].c);
            r=max(r,pre[i].c);
        }
        // printf("l=%d r=%d\n",l,r);
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(check(n,m,mid)) ansans=mid,l=mid+1;
            else r=mid-1;
        }
        if(ansans==-1) printf("streaming not possible.\n");
        else printf("%d kbps\n",ansans);
    }
    return 0;
}

例题23 蚂蚁

给出n个白点和n个黑点的坐标,要求用n条不相交的线段把它们连接起来,其中每条线段恰好连接一个白点和一个黑点,每个点恰好连接到一条线段。
对于二维平面上的点,如果要用不相交的线连起来,最后线段总长度最小的方案(即二分图最佳完美匹配)就是解
题面pdf上的样例输出给错了。
我用的dinic跑的。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define MAXN 310
#define INF 1e9
#define S 0
#define T 2*n+1
using namespace std;
int n,m,t=1,c;
int head[MAXN],cur[MAXN],done[MAXN],pre_e[MAXN],pre_v[MAXN];
double f;
double dis[MAXN];
struct Edge{int nxt,to,dis;double cost;}edge[MAXN*MAXN*2];
struct Node{int x,y;}node[MAXN];
inline double dist(int a,int b){
    return sqrt(1.0*(node[a].x-node[b].x)*(node[a].x-node[b].x)+1.0*(node[a].y-node[b].y)*(node[a].y-node[b].y));
}
inline void add(int from,int to,int dis,double cost)
{
    edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis,edge[t].cost=cost,head[from]=t;
    edge[++t].nxt=head[to],edge[t].to=from,edge[t].dis=0,edge[t].cost=-cost,head[to]=t;
}
inline bool spfa()
{
    queue<int>q; 
    for(int i=0;i<=T;i++) dis[i]=1e9;
    memset(done,0,sizeof(done));
    q.push(S);dis[S]=0;done[S]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();done[u]=0;
        for(int i=head[u];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(edge[i].dis>0.0&&dis[u]+edge[i].cost<dis[v])
            {
                dis[v]=dis[u]+edge[i].cost;
                pre_e[v]=i,pre_v[v]=u;
                if(!done[v])
                    q.push(v),done[v]=1;
            }
        }
    }
    if(dis[T]>=1e9) return false;
    int flow=0x3f3f3f3f;
    for(int i=T;i!=S;i=pre_v[i]) flow=min(flow,edge[pre_e[i]].dis);
    for(int i=T;i!=S;i=pre_v[i]) edge[pre_e[i]].dis-=flow,edge[pre_e[i]^1].dis+=flow;
    f+=flow;
    c+=flow*dis[T];
    return true;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    while(scanf("%d",&n)==1)
    {
        memset(head,0,sizeof(head));
        t=1;
        for(int i=1;i<=n;i++) scanf("%d%d",&node[i].x,&node[i].y);
        for(int i=1;i<=n;i++) scanf("%d%d",&node[i+n].x,&node[i+n].y);
        for(int i=1;i<=n;i++) add(S,i,1,0);//printf("[%d %d] 1 0\n",S,i);
        for(int i=1;i<=n;i++) add(i+n,T,1,0);//printf("[%d %d] 1 0\n",i+n,T);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                add(i,j+n,1,dist(i,j+n));//printf("[%d %d] 1 %.2lf\n",i,j+n,dist(i,j+n));
        while(spfa());
        // printf("c=%d f=%.2lf\n",c,f);
        for(int i=1;i<=n;i++)
        {
            for(int j=head[i];j;j=edge[j].nxt)
            {
                if(edge[j].dis==0&&edge[j].to!=S)
                {
                    printf("%d\n",edge[j].to-n);
                    break;
                }
            }
        }
    }
    return 0;
}

例题24 少林决胜

给定一个N*N的矩阵,每个格子里都有一个正整数\(w(i,j)\)。你的任务是给定每行确定一个整数\(row(i)\),每列也确定一个整数\(col(i)\),使得对于任意格子\((i,j)\)\(w(i,j)\le row(i)+col(j)\)。所有row(i)和col(i)之和应当尽量小。

“还记得KM算法里面的\(l(x)+l(y)>=w(x,y)\)吗?算法结束结束后,所有顶标和是最小的。”
......
于是跑一遍KM就行了QAQ

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define MAXN 510
#define INF 0x3f3f3f3f
using namespace std;
int n,kase,ans;
int w[MAXN][MAXN],lx[MAXN],ly[MAXN],to[MAXN];
bool S[MAXN],T[MAXN];
inline int match(int x)
{
    S[x]=true;
    for(int j=1;j<=n;j++)
        if(lx[x]+ly[j]==w[x][j]&&!T[j])
        {
            T[j]=true;
            if(!to[j]||match(to[j]))
            {
                to[j]=x;
                return true;
            }
        }
    return false;
}
inline void update()
{
    int d=INF;
    for(int i=1;i<=n;i++)
        if(S[i])
            for(int j=1;j<=n;j++)
                if(!T[j])
                    d=min(d,lx[i]+ly[j]-w[i][j]);
    for(int i=1;i<=n;i++)
    {
        if(S[i]) lx[i]-=d;
        if(T[i]) ly[i]+=d;
    }
}
inline void KM()
{
    for(int i=1;i<=n;i++)
    {
        lx[i]=ly[i]=to[i]=0;
        for(int j=1;j<=n;j++) lx[i]=max(lx[i],w[i][j]);
    }
    for(int i=1;i<=n;i++)
    {
        while(233)
        {
            for(int j=1;j<=n;j++) S[j]=T[j]=0;
            if(match(i)) break;
            else update();
        }
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    while(scanf("%d",&n)!=EOF)
    {
        ans=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&w[i][j]);
        KM();
        for(int i=1;i<n;i++) printf("%d ",lx[i]),ans+=lx[i];
        printf("%d\n",lx[n]),ans+=lx[n];
        for(int i=1;i<n;i++) printf("%d ",ly[i]),ans+=ly[i];
        printf("%d\n",ly[n]),ans+=ly[n];
        printf("%d\n",ans);
    }
    return 0;
}

例题25 固定分区内存管理

感觉和这个题差不多。
不过还要输出调度方案......具体请看代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define MAXN 60
#define INF 0x3f3f3f3f
using namespace std;
int n,m,nm,kase;
int start[MAXN],belong[MAXN];
int runtime[MAXN][MAXN],w[MAXN*10][MAXN*10];
int head[MAXN],siz[MAXN],s[MAXN],t[MAXN],number[MAXN];
int l[MAXN*10],lx[MAXN*10],ly[MAXN*10];
bool S[MAXN*10],T[MAXN*10];
vector<int>G[MAXN*10];
inline void add(int from,int to,int dis)
{
    // printf("[%d %d] %d\n",from,to,dis);
    G[from].push_back(to);
    w[from][to]=dis;
}
inline bool match(int x)
{
    S[x]=true;
    for(int i=0;i<G[x].size();i++)
    {
        int v=G[x][i];
        if(lx[x]+ly[v]==w[x][v]&&!T[v])
        {
            T[v]=true;
            if(!l[v]||match(l[v]))
            {
                l[v]=x;
                return true;
            }
        }
    }
    return false;
}
inline void update()
{
    int d=INF;
    for(int i=1;i<=nm;i++)
        if(S[i])
            for(int cur=0;cur<G[i].size();cur++)
            {
                int j=G[i][cur];
                if(!T[j])
                    d=min(d,lx[i]+ly[j]-w[i][j]);
            }
    for(int i=1;i<=nm;i++)
    {
        if(S[i]) lx[i]-=d;
        if(T[i]) ly[i]+=d;
    }
}
inline void solve()
{
    for(int i=1;i<=nm;i++)
    {
        lx[i]=ly[i]=l[i]=0;
        for(int j=1;j<=nm;j++)
            if(w[i][j]>lx[i])
                lx[i]=w[i][j];
    }
    for(int i=1;i<=nm;i++)
    {
        while(233)
        {
            for(int j=1;j<=nm;j++) S[j]=T[j]=0;
            if(match(i)) break;
            else update();
        }
    }
}
inline void print()
{
    int all_time=0;
    for(int i=1;i<=m;i++)
    {
        vector<int>programs;
        for(int j=1;j<=n;j++)
        {
            int r=n*(i-1)+j;
            int cur=l[r];
            if(cur>n) break;
            programs.push_back(cur);
            belong[cur]=i;
            all_time-=w[cur][r]; 
        }
        reverse(programs.begin(),programs.end());
        int cur_time=0;
        for(int j=0;j<programs.size();j++)
        {
            start[programs[j]]=cur_time;
            cur_time+=runtime[programs[j]][i];
        }
    }
    printf("Case %d\n",++kase);
    printf("Average turnaround time = %.2lf\n",(double)all_time/n);
    for (int i=1;i<=n;i++) 
        printf("Program %d runs in region %d from %d to %d\n",i,belong[i],start[i],start[i]+runtime[i][belong[i]]);
    printf("\n");
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    while(scanf("%d%d",&m,&n)==2)
    {
        if(n==0&&m==0) break;
        nm=n*m;
        for(int i=1;i<=nm;i++) G[i].clear();
        memset(w,0,sizeof(w));
        for(int i=1;i<=m;i++) scanf("%d",&siz[i]);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&number[i]);
            for(int j=1;j<=number[i];j++) scanf("%d%d",&s[j],&t[j]);
            for(int j=1;j<=m;j++)
            {
                runtime[i][j]=-1;
                if(siz[j]<s[1]) continue;
                for(int k=1;k<=number[i];k++)
                {
                    if(siz[j]<s[k+1]||k==number[i])
                    {runtime[i][j]=t[k];break;}
                }
            }
        }
        // for(int i=1;i<=n;i++)
        //     for(int j=1;j<=m;j++)
        //         printf("runtime[%d][%d]=%d\n",i,j,runtime[i][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(runtime[i][j]!=-1)
                    for(int k=1;k<=n;k++)
                        add(i,(j-1)*n+k,-runtime[i][j]*k);
        for(int i=n+1;i<=nm;i++)
            for(int j=1;j<=nm;j++)
                add(i,j,1);
        solve();
        print();
    }
    return 0;
} 

例题26 女士的选择

稳定婚姻模板题

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstring>
#include<algorithm>
#include<queue>
#define MAXN 1010
using namespace std;
int T,n,kase;
int to_girl[MAXN],to_boy[MAXN];
int a[MAXN][MAXN],order[MAXN][MAXN],nxt[MAXN];
queue<int>q;
inline void solve(int x,int y)
{
    int cur=to_boy[y];
    if(cur)
    {
        to_girl[cur]=0;
        q.push(cur);
    }
    to_girl[x]=y,to_boy[y]=x;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&T);
    while(T--)
    {
        while(!q.empty()) q.pop();
        memset(to_girl,0,sizeof(to_girl));
        memset(to_boy,0,sizeof(to_boy));
        if(!kase) kase++;
        else printf("\n");
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                scanf("%d",&a[i][j]);
            nxt[i]=1;
            q.push(i);
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                int x;
                scanf("%d",&x);
                order[i][x]=j;
            }
        while(!q.empty())
        {
            int now=q.front();q.pop();
            int now_to=a[now][nxt[now]++];
            if(!to_boy[now_to]||order[now_to][now]<order[now_to][to_boy[now_to]]) 
                solve(now,now_to);
            else q.push(now);
        }
        for(int i=1;i<=n;i++) printf("%d\n",to_girl[i]);
    }
    return 0;
}
posted @ 2019-05-12 10:34  风浔凌  阅读(233)  评论(0编辑  收藏  举报