【XSY1287】【BZOJ3816】【清华集训2014】矩阵变换 稳定婚姻问题

来源:互联网 发布:数据抓取工具 编辑:程序博客网 时间:2024/06/06 03:21

题目描述

  给出一个nm列的矩阵A, 保证满足以下性质:

   1.m>n

   2.矩阵中每个数都是[0,n]中的自然数。

   3.每行中,[1,n]中每个自然数都恰好出现一次。这意味着每行中0恰好出现mn次。

   4. 每列中,[1,n]中每个自然数至多出现一次。

现在我们要在每行中选取一个非零数,并把这个数之后的数赋值为这个数。我们希望保持上面的性质4,即每列中,[1,n]中每个自然数仍然至多出现一次。

  n200,m400

题解

  建立稳定婚姻问题的模型。

  把行看成男士,把数看成女士。每行喜欢出现靠左的数,每个数喜欢出现位置(这个数在这行中出现的位置)靠右的行。

  为什么这样一定合法?

  假设有这样的情况:

x:uuuuuuuuuuuy:     u        vvvvv

  那么在第y行中,y会更喜欢u(因为比v出现位置靠左)。u也会更喜欢y(因为出现位置靠右),那么就不是一个合法解。

  其实比读入还快。

  时间复杂度:O(nm)

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<ctime>#include<utility>#include<queue>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> pii;void rd(int &s){    int c;    while((c=getchar())<'0'||c>'9');    s=c-'0';    while((c=getchar())>='0'&&c<='9')        s=s*10+c-'0';}int a[210][410];int n,m;int b[210][210];int now[210];int c[210][210];int d[210];queue<int> q;void solve(){//  scanf("%d%d",&n,&m);    rd(n);    rd(m);    int i,j;    memset(now,0,sizeof now);    for(i=1;i<=n;i++)        for(j=1;j<=m;j++)        {//          scanf("%d",&a[i][j]);            rd(a[i][j]);            if(a[i][j])            {                b[i][++now[i]]=a[i][j];                c[a[i][j]][i]=j;            }        }    for(i=1;i<=n;i++)    {        q.push(i);        now[i]=1;    }    memset(d,0,sizeof d);    while(!q.empty())    {        int x=q.front();        q.pop();        int v=b[x][now[x]];        if(d[v]&&c[v][x]<c[v][d[v]])        {            now[x]++;            q.push(x);        }        else        {            if(d[v])                q.push(d[v]);            d[v]=x;        }    }    for(i=1;i<=n;i++)        printf("%d ",b[i][now[i]]);    printf("\n");}int main(){    freopen("d2t3.in","r",stdin);    freopen("d2t3.out","w",stdout);    int t;//  scanf("%d",&t);    rd(t);    while(t--)        solve();    return 0;}