Luogu P4134 [BJOI2012] 连连看 题解 [ 紫 ] [ 二分图最大权匹配 ] [ 费用流 ] [ 打表 ]

连连看:傻逼题,结论仅在数据范围内正确。开局一个一般图最大匹配,结论全靠猜。

思路

这题显然是一个一般图最大权匹配问题。。。但是开花算法太难了,显然不是正解。正常做法应该是二分图最大权匹配问题。

但是怎么证明这玩意是个二分图呢?数学严谨证明我肯定是想不出来的。我们考虑打表,先把图建出来,然后跑二分图染色,很容易发现 \(a=1,b=1000\) 的时候一定是二分图。然后这题跑二分图最大权匹配就做完了。

实际上这个结论是错误的,只是在 \(n \le 10^3\) 的时候成立,在 \(a=1,b=6109\) 的时候就不是二分图了。这题出题人就是他妈的傻逼。

感觉这个猜结论猜建出的图是二分图和一双木棋十分相似,一个猜图的形态,一个猜 dp 的合法状态数,都是灵光一现又很难绷的观察。

我采用了费用流实现,时间复杂度为 EK 或者 Dinic 的复杂度。

代码

打表代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int N=10005;
int a,b,c[N];
bool legal=1;
vector<int>g[N];
void dfs(int u)
{
    for(auto v:g[u])
    {
        if(c[v]==0)
        {
            c[v]=3-c[u];
            dfs(v);
        }
        else if(3-c[u]!=c[v])legal=0;
    }
}
int main()
{
    //freopen("sample.in","r",stdin);
    //freopen("sample.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>a>>b;
    for(int i=a;i<=b;i++)
    {
        for(int j=i+1;j<=b;j++)
        {
            int pf=j*j-i*i;
            if(int(sqrt(1.0*pf))*int(sqrt(1.0*pf))==pf)
            {
                int z=int(sqrt(1.0*pf));
                if(__gcd(z,i)==1)
                {
                    g[j].push_back(i);
                    g[i].push_back(j);                 
                }
            }
        }
    }
    for(int i=a;i<=b;i++)
    {
        if(c[i]==0)
        {
            c[i]=1;
            dfs(i);
        }
    }
    cout<<legal;
    return 0;
}

跑出来 \(a=1,b=6109\) 的时候就不是二分图了。

正解代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int N=1005,M=2000005;
const ll inf=0x3f3f3f3f3f3f3f3f;
int a,b,c[N],s,t;
bool legal=1;
vector<int>g[N];
void dfs(int u)
{
    for(auto v:g[u])
    {
        if(c[v]==0)
        {
            c[v]=3-c[u];
            dfs(v);
        }
        else if(3-c[u]!=c[v])legal=0;
    }
}
int h[N],cur[N],idx=1;
struct Edge{
    int v,ne;
    ll c,w;
}e[M];
void add(int u,int v,ll c,ll w)
{
    e[++idx]={v,h[u],c,w};
    h[u]=idx;
}
void addeg(int u,int v,ll c,ll w)
{
    add(u,v,c,w);
    add(v,u,0,-w);
}
ll cost,dis[N];
bitset<N>vis;
bool SPFA()
{
    memset(dis,-0x3f,sizeof(dis));
    vis.reset();
    queue<int>q;
    q.push(s);
    vis[s]=1;
    dis[s]=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=h[u];i;i=e[i].ne)
        {
            int v=e[i].v;ll c=e[i].c,w=e[i].w;
            if(dis[v]<dis[u]+w&&c)
            {
                dis[v]=dis[u]+w;
                if(vis[v]==0)
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return (dis[t]>=(-inf/2));
}
ll dfs(int u,ll mf)
{
    if(u==t)return mf;
    ll sm=0;
    vis[u]=1;
    for(int i=cur[u];i;i=e[i].ne)
    {
        int v=e[i].v;ll c=e[i].c,w=e[i].w;
        cur[u]=i;
        if(vis[v]==0&&c&&dis[v]==dis[u]+w)
        {
            ll res=dfs(v,min(c,mf));
            cost+=w*res;
            e[i].c-=res;
            e[i^1].c+=res;
            mf-=res;
            sm+=res;
            if(mf==0)break;
        }
    }
    if(sm==0)dis[u]=inf;
    return sm;
}
void dinic()
{
    ll flow=0;
    while(SPFA())
    {
        memcpy(cur,h,sizeof(h));
        vis.reset();
        flow+=dfs(s,inf);
    }
    cout<<flow<<" "<<cost;
}
int main()
{
    //freopen("sample.in","r",stdin);
    //freopen("sample.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>a>>b;
    for(int i=a;i<=b;i++)
    {
        for(int j=i+1;j<=b;j++)
        {
            int pf=j*j-i*i;
            if(int(sqrt(1.0*pf))*int(sqrt(1.0*pf))==pf)
            {
                int z=int(sqrt(1.0*pf));
                if(__gcd(z,i)==1)
                {
                    g[j].push_back(i);
                    g[i].push_back(j);                 
                }
            }
        }
    }
    for(int i=a;i<=b;i++)
    {
        if(c[i]==0)
        {
            c[i]=1;
            dfs(i);
        }
    }
    s=1001,t=1002;
    for(int i=a;i<=b;i++)
    {
        if(c[i]==1)addeg(s,i,1,0);
        else addeg(i,t,1,0);
    }
    for(int i=a;i<=b;i++)
    {
        if(c[i]==2)continue;
        for(auto v:g[i])
        {
            addeg(i,v,1,i+v);
        }
    }
    dinic();
    return 0;
}
posted @ 2025-04-20 16:43  KS_Fszha  阅读(16)  评论(0)    收藏  举报