2018-3-20模拟考试 备用题

Posted on 2018-03-28 22:18  SirKnight  阅读(141)  评论(0)    收藏  举报

二分答案,每次将小于等于当前值的边加入二分图中,看最大流能否大于等于n-k+1,反着来是不行的,因为如果最大流大于k-1,不代表只能向上二分,可以不取最大流。

#include <cstdio>//输入字符串必需 
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define ll long long int

const int maxn=90001;

struct node
{
    string s;
    ll len,x,y;
}p[maxn];

ll vis[301][301],g[301],d[301];
ll n,k,top=0,ans;

bool cmp(node a,node b)//字符串排序 
{
    if(a.len==b.len)
        return a.s<b.s;
    return a.len<b.len;
}

bool dfs(ll x)
{
    ll i;
    for(i=1;i<=n;i++)
    {
        if(vis[x][i]&&!d[i])
        {
            d[i]=1;//这里改变d 
            if(!g[i]||dfs(g[i]))
            {
                g[i]=x;
                return 1;
            }
        }
    }
    return 0;
}

bool check(ll x)
{
    ll i;
    for(i=1;i<=top;i++)
    {
        if(p[x].len==p[i].len)
        {
            if(p[x].s>=p[i].s)
                vis[p[i].x][p[i].y]=1;
            else
                vis[p[i].x][p[i].y]=0;//必需清0 
        }
        else if(p[x].len>p[i].len)
            vis[p[i].x][p[i].y]=1;
        else 
            vis[p[i].x][p[i].y]=0;
    }
    memset(g,0,sizeof(g));
    for(i=1;i<=n;i++)
    {
        memset(d,0,sizeof(d));
        dfs(i);
    }
    ll sum=0;
    for(i=1;i<=n;i++)
    {
        if(g[i])
            sum++;
    }
    if(sum>=n-k+1)//(最大流的性质)至少是第k大,所以向下二分 
        return 1;
    return 0;
}

int main()
{
    scanf("%lld%lld",&n,&k);
    ll i,j;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            cin>>p[++top].s;//字符串cin 
            p[top].len=(p[top].s).size();//字符串长度 
            p[top].x=i,p[top].y=j;
        }
    }
    sort(p+1,p+top+1,cmp);
    ll l=1,r=top;//离散化 
    while(l<=r)
    {
        ll mid=(l+r)/2;
        if(check(mid))
        {
            ans=mid;
            r=mid-1;
        }
        else
            l=mid+1;  
    }
    cout<<p[ans].s<<endl;//字符串cout 
    return 0;
}