《hdu2819》

看到题目想了一会感觉就是二分图的方向,但是这个图的建模抽象了好久。

后面我直接对等于1的行列连边,就发现了这样连边是合法的。且需要明白的是交换行的操作实际上是和交换列等价的,所以我们只需要去交换列判断是否成立即可

对于每个行i,我们要找到一列能使他这一行的第i列为1,那么仔细思考之后发现,其实就是找到的这一列和第i列交换。

然后就可以建图去匹配了。

这里还有一个麻烦的地方,就是在一次交换之后,可能已经改变了原有的行列。

这时候需要转移匹配。

也就是说,如果当前为1 匹配 4,4 匹配 2.

那么在第一次交换1,4后1的匹配应该变成2,而4的匹配应该变成4.

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 5e6 + 5;
const LL Mod = 1e9 + 7;
#define INF 1e9
#define dbg(x) cout << "now this num is " << x << endl;
inline LL read()
{
    LL x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}
    return x * f;
}
int n,match[105],vis[105];
vector<int> G[105];
bool Find(int x)
{
    for(auto v : G[x])
    {
        if(vis[v]) continue;
        vis[v] = 1;
        if(match[v] == -1 || Find(match[v]))
        {
            match[v] = x;
            return true;
        }
    }
    return false;
}
bool solve()
{
    int ans = 0;
    memset(match,-1,sizeof(match));
    for(int i = 1;i <= n;++i)
    {
        memset(vis,0,sizeof(vis));
        if(Find(i)) ans++;
    }
    return ans == n;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i = 1;i <= n;++i) G[i].clear();
        for(int i = 1;i <= n;++i)
            for(int j = 1;j <= n;++j)
            {
                int x;x = read();
                if(x == 1) G[i].push_back(j);
            }
        if(solve())
        {
            vector<pii> vec;
            for(int i = 1;i <= n;++i)
            {
                if(i != match[i])
                {
                    for(int j = 1;j <= n;++j)
                    {
                        if(match[j] == i)
                        {
                            vec.push_back(pii{i,j});
                            swap(match[i],match[j]);
                            break;
                        }
                    }
                }
            }
            printf("%d
",vec.size());
            for(int i = 0;i < vec.size();++i) printf("C %d %d
",vec[i].first,vec[i].second);
        }
        else printf("-1
");
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zwjzwj/p/13925836.html