FR #4题解

A.

  显然枚举每个点然后极角排序,然后two-pointer即可。

     但是这货写着比较复杂啊。

B.

  网络流。首先考虑没有阻挡,那么按行-列建二分图,然后连很多条边费用不同,代表当前的花费,然后最小费用最大流。

      如果有阻挡?拆下点就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxv 200050
#define maxe 400050
#define maxn 55
#define inf 1000000007
using namespace std;
int n,k,map[maxn][maxn],bel1[maxn][maxn],bel2[maxn][maxn],cnt[maxv],s=0,t,ans=0,ret=0;
int nume=1,g[maxv],dis[maxv],prev[maxv],pree[maxv];
bool vis[maxv];
queue <int> q;
struct edge
{
    int v,f,c,nxt;
}e[maxe];
char ss[maxn];
void addedge(int u,int v,int f,int c)
{
    e[++nume].v=v;e[nume].f=f;e[nume].c=c;e[nume].nxt=g[u];g[u]=nume;
    e[++nume].v=u;e[nume].f=0;e[nume].c=-c;e[nume].nxt=g[v];g[v]=nume;
}
void build()
{
    for (int i=1;i<=n;i++)
    {
        int pre=0;
        for (int j=1;j<=n;j++)
        {
            if ((pre^map[i][j]) && (map[i][j])) ret++;
            if (map[i][j]) {bel1[i][j]=ret;cnt[ret]++;}pre=map[i][j];
        }
    }
    for (int i=1;i<=ret;i++)
        for (int j=0;j<cnt[i];j++)
            addedge(s,i,1,j);
    int regis=ret+1;
    for (int j=1;j<=n;j++)
    {
        int pre=0;
        for (int i=1;i<=n;i++)
        {
            if ((pre^map[i][j]) && (map[i][j])) ret++;
            if (map[i][j]) {bel2[i][j]=ret;cnt[ret]++;}pre=map[i][j];
        }
    }
    for (int i=regis;i<=ret;i++)
        for (int j=0;j<cnt[i];j++)
            addedge(i,t,1,j);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
        {
            if (!map[i][j]) continue;
            addedge(bel1[i][j],bel2[i][j],1,0);
        }
}
void spfa()
{
    while (!q.empty()) q.pop();
    for (int i=s;i<=ret;i++) {vis[i]=false;dis[i]=inf;prev[i]=0;pree[i]=0;}
    dis[s]=0;vis[s]=true;prev[t]=0;pree[t]=0;dis[t]=inf;vis[t]=false;q.push(s);
    while (!q.empty())
    {
        int head=q.front();q.pop();
        for (int i=g[head];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if ((e[i].f>0) && (dis[v]>dis[head]+e[i].c))
            {
                dis[v]=dis[head]+e[i].c;
                pree[v]=i;prev[v]=head;
                if (!vis[v]) {vis[v]=true;q.push(v);}
            }
        }
        vis[head]=false;
    }
}
int dinic()
{
    int dt=inf,u=t;
    while (u!=s)
    {
        dt=min(dt,e[pree[u]].f);
        u=prev[u];
    }
    u=t;
    while (u!=s)
    {
        e[pree[u]].f-=dt;e[pree[u]^1].f+=dt;
        u=prev[u];
    }
    return dis[t]*dt;
}
int main()
{
    scanf("%d%d",&n,&k);t=200000;
    for (int i=1;i<=n;i++)
    {
        scanf("%s",ss+1);
        for (int j=1;j<=n;j++)
            map[i][j]=(ss[j]=='.');
    }
    build();
    for (int i=1;i<=k;i++)
    {
        spfa();
        ans+=dinic();
    }
    printf("%d
",ans);
    return 0;
}

 C.

  仿佛和什么后缀数组有关。。。弃坑啦。

原文地址:https://www.cnblogs.com/ziliuziliu/p/6276933.html