1437C - Chef Monocarp 二分图思路,2021秦皇岛F

72 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 19 天,点击查看活动详情

Problem - 1437C - Codeforces 二分图思路

T是可以从1~inf取值的,然后可以发现t[i]最大是n,那么最大就是200,考虑最极端的情况T也是只要取到n+100就可以了,然后问题就转化成了n个点去匹配T[1,n+100]这些点中的n个点使得价值最小,那么刚学的KM其实是可以用一下的,KM是求的最大完美匹配,那我们把价值都变成负数跑一边最大,然后答案再取个负就是最小的价值了;

另外这个算法要求两边点相同,那我们就把n也扩大100个容量,这多出来的100个点让他们与T的那些点的价值都为0即可

int tt,ta[N],tb[N],n;
int mb[N],vb[N],ka[N],kb[N],p[N],c[N],e[N][N];
int qf,qb,q[N];
void bfs(int u)
{
    int a,v=0,vl=0,d;
    for(int i=1;i<=n;i++) p[i]=0,c[i]=inf;
    mb[v]=u;
    do
    {
        a=mb[v],d=inf,vb[v]=1;
        for(int b=1;b<=n;b++)
            if(!vb[b])
        {
            if(c[b]>ka[a]+kb[b]-e[a][b])
                c[b]=ka[a]+kb[b]-e[a][b],p[b]=v;
            if(c[b]<d) d=c[b],vl=b;
        }
        for(int b=0;b<=n;b++)
            if(vb[b]) ka[mb[b]]-=d,kb[b]+=d;
        else c[b]-=d;
        v=vl;
    }while(mb[v]);
    while(v) mb[v]=mb[p[v]],v=p[v];
}
int KM()
{
    for(int i=1;i<=n;i++) mb[i]=ka[i]=kb[i]=0;
    for(int a=1;a<=n;a++)
    {
        for(int b=1;b<=n;b++) vb[b]=0;
        bfs(a);
    }
    int res=0;
    for(int b=1;b<=n;b++) res+=e[mb[b]][b];
    return res;
}
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    cin>>tt;
    while(tt--)
    {
        cin>>n;

        for(int i=1;i<=n;i++) cin>>ta[i];
        for(int i=1;i<=n+100;i++) tb[i]=i;
        for(int a=1;a<=n+100;a++)
            for(int b=1;b<=n+100;b++) e[a][b]=-inf;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n+100;j++)
                e[i][j]=-abs(tb[j]-ta[i]);
        for(int i=n+1;i<=n+100;i++)
            for(int j=1;j<=n+100;j++)
            e[i][j]=0;
        n=n+100;
        int ans=KM();
        cout<<-ans<<endl;
    }
    return 0;
}

还有一个dp的思路,f[i][j]是第i个菜第j个时间拿所需要的最小价值,这个需要先对数组排序,排序之后可以发现第i个菜在最优情况下一定是要在第i-1个菜之后取的,所以第i个菜是可以由第i-1个菜转移过来的,对于第j个时间我们可以考虑到底用不用这个时间,不用的话就是f[i][j]=f[i][j-1],用的话就是f[i][j]=min(f[i][j],f[i-1][j-1]+abs(j-a[i]));

C. Chef Monocarp(思维,dp)_H-w-H的博客-CSDN博客_c. chef monocarp

int tt,n,a[N],f[N][N];
signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    cin>>tt;
    while(tt--)
    {
        cin>>n;
        for(int i=0;i<=n+100;i++)
            for(int j=0;j<=n+100;j++)
            f[i][j]=inf;
        for(int i=0;i<=n+100;i++) f[0][i]=0;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n+100;j++)
            {
                f[i][j]=f[i][j-1];
                f[i][j]=min(f[i][j],f[i-1][j-1]+abs(a[i]-j));
                //cout<<"f[i][j]="<<f[i][j]<<" f[i-1][j-1]="<<f[i-1][j-1]<<" i="<<i<<" j="<<j<<" a[i]="<<a[i]<<endl;
            }
        int ans=inf;
        for(int i=1;i<=n+100;i++) ans=min(ans,f[n][i]);
        cout<<ans<<endl;
    }
    return 0;
}

F - Forest Program 无向图找环

只要看dfs的深度就可以,如果当前节点是u,那么与u右边的那些点如果没被访问过就去访问,如果访问过且vis[v]=1,那么就说明遇到了环,环的大小就是dep[u]-dep[v]+1;如果vis[v]=2那就说明是环,但是之前就已经访问过了,就不用再访问了,循环结束后将vis[u]=2,表示这个点所在的环都被访问过了

int qpow(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int head[N],cnt;
struct Edge
{
    int to,next;
}e[N];
void addedge(int from,int to)
{
    e[++cnt].to=to;
    e[cnt].next=head[from];
    head[from]=cnt;
}
int n,m,dep[N],siz[N],tot,vis[N];
void dfs(int u,int fa)
{
    dep[u]=dep[fa]+1;
    vis[u]=1;
    for(int i=head[u];i;i=e[i].next)
    {
        int j=e[i].to;
        if(j==fa) continue;
        if(vis[j]==1)
        {
            siz[++tot]=dep[u]-dep[j]+1;
            continue;
        }
        else if(vis[j]==2) continue;
        dfs(j,u);
    }
    vis[u]=2;
}
signed main()
{
    //cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int u,v;cin>>u>>v;
        addedge(u,v);
        addedge(v,u);

    }
    for(int i=1;i<=n;i++)
        {
            if(!vis[i]) dfs(i,0);
        }
    int q=m,ans=1;
    for(int i=1;i<=tot;i++)
    {
        ans=ans*(qpow(2,siz[i])-1)%mod;
        q-=siz[i];
    }
    ans=ans*qpow(2,q)%mod;
    cout<<ans<<endl;
    return 0;
}