模板temp1

本文深入剖析了多种经典算法,包括搜索算法、树状数组、线段树等数据结构的应用实例,以及AC自动机、马拉车算法的实现细节。通过具体题目介绍了算法的设计思路与优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
using namespace std;

//hdu 5113 搜索
//这道题就是搜索,剪枝优化是如果当前未染色的点数为x,(x+1)/2<max(col[i]),就可以return了。
int n,m,k;
int flag;
int map[6][6];
int ca;
struct sa{
    int num,index;
}a[130];
int cmp(const sa a,const sa b)
{
    return (a.num)>(b.num);
}

void ccout()
{
    printf("Case #%d:\nYES\n",ca);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if( j==m)printf("%d\n",map[i][j]);
            else printf("%d ",map[i][j]);
}

void dfs(int x,int y)
{
    for(int i=1;i<=k;i++)
        if(flag==-1)
            return;
        else
            if(a[i].num)
            {
                if(map[x-1][y]!=a[i].index&&map[x][y-1]!=a[i].index)
                {
                    a[i].num--;
                    map[x][y]=a[i].index;
                    
                    if(x==n&&y==m&&flag!=-1)
                    {
                        flag=-1;
                        ccout();
                        return;
                    }
                    if(y==m)
                        dfs(x+1,1);
                    else
                        dfs(x,y+1);
                    a[i].num++;
                }
            }
}

int main()
{
    int t;
    cin>>t;
    for(int i=1;i<=t;++i)
    {
        ca=i;
        cin >>n>>m>>k;
        for(int _i=1;_i<=k;++_i)
        {
            cin>>a[_i].num;
            a[_i].index=_i;
        }
        sort(a+1,a+k+1,cmp);
        if(a[1].num>(n*m+1)/2)
        {
            printf("Case #%d:\nNO\n",i);
            continue;
        }
        flag=0;
        dfs(1,1);
    }
    
    return 0;
}


//poj 2352 stars 树状数组
int level[40005],sum[40005];//sum[i]中装的是x不大于i的点的个数
int lowbit(int i)
{  return i&(-i);
}
int getsum(int i)
{
    int s=0;
    for(;i>0;i-=lowbit(i))
        s+=sum[i];
    return s;
}
void update(int x)
{
    while(x<40005)
    {
        sum[x]++;
        x+=lowbit(x);
    }
}
int main()
{
    int n,x,y;
    while(scanf("%d",&n)!=-1)
    {
        memset(sum,0,sizeof(sum));
        memset(level,0,sizeof(level));
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            level[getsum(x+1)]++;
            update(x+1);
        }
        for(int i=0;i<n;++i)
            printf("%d\n",level[i]);
    }
        return 0;
}

//RMQ POJ3264
#define MAXN 200005
#define INF 10000000
int nMax,nMin;//记录最大最小值
struct Node
{
    int l,r;//区间的左右端点
    int nMin,nMax;//区间的最小值和最大值
}segTree[MAXN*3];
int a[MAXN];
void Build(int i,int l,int r)//在结点i上建立区间为(l,r)
{
    segTree[i].l=l;
    segTree[i].r=r;
    if(l==r)//叶子结点
    {
        segTree[i].nMin=segTree[i].nMax=a[l];
        return;
    }
    int mid=(l+r)>>1;
    Build(i<<1,l,mid);
    Build(i<<1|1,mid+1,r);
    segTree[i].nMin=min(segTree[i<<1].nMin,segTree[i<<1|1].nMin);
    segTree[i].nMax=max(segTree[i<<1].nMax,segTree[i<<1|1].nMax);
}
void Query(int i,int l,int r)//查询结点i上l-r的最大值和最小值
{
    if(segTree[i].nMax<=nMax&&segTree[i].nMin>=nMin)  return;
    if(segTree[i].l==l&&segTree[i].r==r)
    {
        nMax=max(segTree[i].nMax,nMax);
        nMin=min(segTree[i].nMin,nMin);
        return;
    }
    int mid=(segTree[i].l+segTree[i].r)>>1;
    if(r<=mid)   Query(i<<1,l,r);
    else if(l>mid)  Query(i<<1|1,l,r);
    else
    {
        Query(i<<1,l,mid);
        Query(i<<1|1,mid+1,r);
    }
}
int main()
{
    int n,q;
    int l,r;
    int i;
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        Build(1,1,n);
        for(i=1;i<=q;i++)
        {
            scanf("%d%d",&l,&r);
            nMax=-INF;nMin=INF;
            Query(1,l,r);
            printf("%d\n",nMax-nMin);
        }
    }
    return 0;
}

//poj 2528
//海报重叠
int n,cnt;
const int maxn = 10000+10;

struct node
{
    int l,r,n;//n统计颜色
} a[maxn<<2];

struct kode
{
    int point,num;//point记录区间的边,num记录位置
} s[maxn<<2];

int map[maxn<<1][2],ans,flag[maxn<<1];

int cmp(kode x,kode y)
{
    return x.point<y.point;
}

void init(int l,int r,int i)//建树
{
    a[i].l = l;
    a[i].r = r;
    a[i].n = 0;
    if(l!=r)
    {
        int mid = (l+r)>>1;
        init(l,mid,2*i);
        init(mid+1,r,2*i+1);
    }
}

void insert(int i,int l,int r,int m)
{
    if(a[i].l == l && a[i].r == r)//找到了区间,更新这个区间的颜色
    {
        a[i].n = m;
        return;
    }
    int mid = (a[i].l+a[i].r)>>1;
    if(a[i].n>0)//重点注意,如果这个区间被访问了,并且这个区间有颜色,就要将这个区间的颜色更新到其左右孩子的节点,并且要将这个区间的颜色清空,这样才能算是覆盖
    {
        a[2*i].n = a[2*i+1].n = a[i].n;
        a[i].n = 0;
    }
    if(l>=a[2*i+1].l)
        insert(2*i+1,l,r,m);
    else if(r<=a[2*i].r)
        insert(2*i,l,r,m);
    else
    {
        insert(2*i,l,mid,m);
        insert(2*i+1,mid+1,r,m);
    }
}

void solve(int i)
{
    if(a[i].n)//如果有这个区间有颜色了,马上停止访问并返回,因为下面的无论有没有颜色都是已经被覆盖的了
    {
        if(!flag[a[i].n])//如果有颜色且没被统计过的,就统计一次
        {
            ans++;
            flag[a[i].n] = 1;
        }
        return;
    }
    solve(2*i);
    solve(2*i+1);
    return;
}

int main()
{
    int t,i,j;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i = 0; i<n; i++)//离散化
        {
            scanf("%d%d",&map[i][0],&map[i][1]);
            s[2*i].point = map[i][0];
            s[2*i+1].point = map[i][1];
            s[2*i].num = -(i+1);
            s[2*i+1].num = i+1;
        }
        sort(s,s+2*n,cmp);
        int tmp = s[0].point,cnt = 1;
        for(i = 0; i<2*n; i++)
        {
            if(tmp != s[i].point)//如果和前面的不同,这迭代加1
            {
                cnt++;
                tmp = s[i].point;
            }
            if(s[i].num<0)
                map[-s[i].num-1][0] = cnt;
            else
                map[s[i].num-1][1] = cnt;
        }
        init(1,cnt,1);
        for(i = 0; i<n; i++)
            insert(1,map[i][0],map[i][1],i+1);
        memset(flag,0,sizeof(flag));
        ans = 0;
        solve(1);
        printf("%d\n",ans);
    }
    
    return 0;
}

//poj 3468线段树+区间更新
#define MAX 110000
#define LL long long
using namespace std;
LL n,m;
LL ans;
struct Tree
{
    LL l,r;
    LL sum,add;
};
Tree tree[MAX*3];

void pushup(LL x)
{
    LL tmp=2*x;
    tree[x].sum=tree[tmp].sum+tree[tmp+1].sum;
}


void pushdown(LL x)
{
    LL tmp=2*x;
    tree[tmp].add+=tree[x].add;
    tree[tmp+1].add+=tree[x].add;
    tree[tmp].sum+=tree[x].add*(tree[tmp].r-tree[tmp].l+1);
    tree[tmp+1].sum+=tree[x].add*(tree[tmp+1].r-tree[tmp+1].l+1);
    tree[x].add=0;
}

void build(int l,int r,int x)
{
    tree[x].l=l;
    tree[x].r=r;
    tree[x].add=0;
    if(l==r)
    {
        scanf("%lld",&tree[x].sum);
        return ;
    }
    int tmp=x<<1;
    int mid=(l+r)>>1;
    build(l,mid,tmp);
    build(mid+1,r,tmp+1);
    pushup(x);	 //如果在建树的过程中给sum赋值,记得后面要pushup
}


void update(LL l,LL r,LL c,LL x)
{
    if(r<tree[x].l||l>tree[x].r)
        return ;
    if(l<=tree[x].l&&r>=tree[x].r)
    {
        tree[x].add+=c;
        tree[x].sum+=c*(tree[x].r-tree[x].l+1);
        return ;
    }
    if(tree[x].add)
        pushdown(x);
    LL tmp=x<<1;
    update(l,r,c,tmp);	//  !!!
    update(l,r,c,tmp+1);
    pushup(x);
}


void query(LL l,LL r,LL x)
{
    if(r<tree[x].l||l>tree[x].r)		 //要更新的区间不在该区间上
        return ;
    if(l<=tree[x].l&&r>=tree[x].r)	  //要更新区间包括了该区间
    {
        ans+=tree[x].sum;
        return ;
    }
    if(tree[x].add)
        pushdown(x);
    LL tmp=x<<1;
    LL mid=(tree[x].l+tree[x].r)>>1;
    if(r<=mid)
        query(l,r,tmp);
    else if(l>mid)
        query(l,r,tmp+1);
    else
    {
        query(l,mid,tmp);
        query(mid+1,r,tmp+1);
    }
    //	pushup(x);
}


int main()
{
    //	freopen("cin.txt","r",stdin);
    //	freopen("cout.txt","w",stdout);
    while(~scanf("%lld %lld",&n,&m))
    {
        build(1,n,1);
        char str[5];
        while(m--)
        {
            scanf("%s",str);
            if(str[0]=='Q')
            {
                LL l,r;
                scanf("%lld %lld",&l,&r);
                ans=0;
                query(l,r,1);
                printf("%lld\n",ans);
            }
            else
            {
                LL l,r,c;
                scanf("%lld %lld %lld",&l,&r,&c);
                update(l,r,c,1);
            }
        }
    }
    return 0;
}

//hdu 3308线段树区间合并
#define N 100010
int s[N<<2],mm[N<<2],lm[N<<2],rm[N<<2],len[N<<2];
void update(int l,int r,int w)
{
    int m = (l+r)>>1;
    if(s[m]<s[m+1])
    {
        lm[w] = (lm[w<<1]==len[w<<1])?(lm[w<<1]+lm[w<<1|1]):lm[w<<1];
        rm[w] = (rm[w<<1|1]==len[w<<1|1])?(rm[w<<1|1]+rm[w<<1]):rm[w<<1|1];
        mm[w] = max((rm[w<<1]+lm[w<<1|1]),mm[w<<1]);
        mm[w] = max(lm[w],mm[w]);
        mm[w] = max(rm[w],mm[w]);
        mm[w] = max(mm[w<<1|1],mm[w]);
    }
    else
    {
        lm[w] = lm[w<<1];
        rm[w] = rm[w<<1|1];
        mm[w] = max(mm[w<<1],mm[w<<1|1]);
    }
}
int search(int a,int b,int l,int r,int w)
{
    if(a<=l&&b>=r)
    {
        return mm[w];
    }
    int m = (l+r)>>1;
    if(b<=m)
        return search(a,b,l,m,w<<1);
    if(a>m)
        return search(a,b,m+1,r,w<<1|1);
    int len,ren,ans ;
    len = search(a,b,l,m,w<<1);
    ren = search(a,b,m+1,r,w<<1|1);
    ans = max(len,ren);
    if(s[m]<s[m+1])
    {
        int re;
        re=min(rm[w<<1],m-a+1)+min(lm[w<<1|1],b-m);
        ans=max(re,ans);
    }
    return ans;
}
void build(int l,int r,int w)
{
    len[w] = (r-l+1);
    if(l==r)
    {
        mm[w] = 1;
        lm[w] = 1;
        rm[w] = 1;
        return ;
    }
    int m = (l+r)>>1;
    build(l,m,w<<1);
    build(m+1,r,w<<1|1);
    update(l,r,w);
}
void change(int p,int d,int l,int r,int w)
{
    if(l==r&&l==p)
    {
        return ;
    }
    int m = (l+r)>>1;
    if(p<=m)
        change(p,d,l,m,w<<1);
    else
        change(p,d,m+1,r,w<<1|1);
    update(l,r,w);
}
int main()
{
    int i,j,k,n,m,t,a,b;
    char c;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        for(i = 1; i <= n ; i++)
            scanf("%d",&s[i]);
        build(1,n,1);
        while(m--)
        {
            cin>>c>>a>>b;
            if(c=='U')
            {
                s[a+1] = b;
                change(a+1,b,1,n,1);
            }
            else
            {
                cout<<search(a+1,b+1,1,n,1)<<endl;
            }
        }
    }
    return 0;
}
/*
 注意两个地方 向上更新 和查找的时候
 
 向上更新
 
 1. 左儿子最右边的值 < 右儿子最左边的值
 
 lMax = (左儿子的lMax == 左儿子的len) ? 左儿子的len + 右儿子的lMax : 左儿子的lMax;
 rMax = (右儿子的rMax == 右儿子的len) ? 右儿子的len + 左儿子的rMax : 右儿子的rMax;
 Max  = MAX(左儿子的rMax + 右儿子的lMax, 左儿子的Max, 右儿子的Max, lMax, rMax);
 
 2. 左儿子最右边的值 >= 右儿子最左边的值
 
 lMax = 左儿子的lMax;
 rMax = 右儿子的rMax;
 Max  = MAX(左儿子的Max, 右儿子的Max);
 
 查找的时候 也分开来比较
 */

// ac自动机hdu2896
struct Trie
{
    int next[210*500][128],fail[210*500],end[210*500];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < 128;i++)
            next[L][i] = -1;
        end[L++] = -1;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char s[],int id)
    {
        int len = strlen(s);
        int now = root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][s[i]] == -1)
                next[now][s[i]] = newnode();
            now=next[now][s[i]];
        }
        end[now]=id;
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        for(int i = 0;i < 128;i++)
            if(next[root][i] == -1)
                next[root][i] = root;
            else
            {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            for(int i = 0;i < 128;i++)
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
    bool used[510];
    bool query(char buf[],int n,int id)
    {
        int len = strlen(buf);
        int now = root;
        memset(used,false,sizeof(used));
        bool flag = false;
        for(int i = 0;i < len;i++)
        {
            now = next[now][buf[i]];
            int temp = now;
            while(temp != root)
            {
                if(end[temp] != -1)
                {
                    used[end[temp]] = true;
                    flag = true;
                }
                temp = fail[temp];
            }
        }
        if(!flag)return false;
        printf("web %d:",id);
        for(int i = 1;i <= n;i++)
            if(used[i])
                printf(" %d",i);
        printf("\n");
        return true;
    }
};
char buf[10010];
Trie ac;
int main()
{
    int n,m;
    while(scanf("%d",&n) != EOF)
    {
        ac.init();
        for(int i = 1;i <= n;i++)
        {
            scanf("%s",buf);
            ac.insert(buf,i);
        }
        ac.build();
        int ans = 0;
        scanf("%d",&m);
        for(int i = 1;i <= m;i++)
        {
            scanf("%s",buf);
            if(ac.query(buf,n,i))
                ans++;
        }
        printf("total: %d\n",ans);
    }
    return 0;
}

//hdu 5384 ac自动机
struct Trie
{
    int next[100010][26],fail[210*500],end[210*500];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < 26;i++)
            next[L][i] = -1;
        end[L++] = 0;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(string buf)
    {
        int len = buf.size();
        int now = root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][buf[i]-'a'] == -1)
                next[now][buf[i]-'a'] = newnode();
            now=next[now][buf[i]-'a'];
        }
        end[now]++;
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        for(int i = 0;i < 26 ; i++)
            if(next[root][i] == -1)
                next[root][i] = root;
            else
            {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            for(int i = 0;i < 26;i++)
                if(next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else
                {
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
    
    int query(string buf)
    {
        int len = buf.size();
        int now = root;
        int ans = 0;
        for(int i = 0;i < len;i++)
        {
            now = next[now][buf[i]-'a'];
            int temp = now;
            while(temp != root)
            {
                if(end[temp] != root)
                    ans+=end[temp];
                temp = fail[temp];
            }
        }
        return ans;
    }
};
string buf[10010];
Trie ac;
int main()
{
    //ios::sync_with_stdio(false);
    int n,m,T;
    cin>>T;
    while(T--)
    {
        cin>>n>>m;
        for(int i=0;i<n;i++)
            cin>>buf[i];
        ac.init();
        for(int i=0;i<m;i++)
        {
            string s;
            cin>>s;
            ac.insert(s);
        }
        ac.build();
        for(int i=0;i<n;i++)
            cout<<ac.query(buf[i])<<endl;
    }
    return 0;
}

// 马拉车 回文串hdu3068
#define MAX 110010

char str[MAX],str1[2*MAX];
int mana[2*MAX];
int len;
int ans;

void manacher()
{
    int i,j,k;
    memset(mana,0,sizeof(mana));
    str1[0]='&';
    for(i=0,j=1;str[i]!=0;i++)
    {
        str1[j++]='#';
        str1[j++]=str[i];
    }
    str1[j++]='#';
    str1[j]='*';
    len=j;
    i=1;
    int mx=0,id;
    ans=0;
    for(i=1;i<len;i++)
    {
        if(mx>i) mana[i]=min(mx-i,mana[2*id-i]);
        else mana[i]=1;
        for(;str1[i-mana[i]]==str1[i+mana[i]];mana[i]++);
        if(mana[i]+i>mx)
        {
            mx=mana[i]+i;
            id=i;
        }
        if(mana[i]>ans)
            ans=mana[i];
    }
}

int main(int argc, const char * argv[]) {
    // insert code here...
    while(scanf("%s",str)!=-1)
    {
        //memset(tmp,0,sizeof(tmp));
        //int l =  init(str);
        manacher();
        cout<<ans-1<<endl;
        //memset(str,0,sizeof(str));
    }
    //std::cout << "Hello, World!\n";
    return 0;
}

//2 3 4 4 3 2 2 3 4回文串
//hdu 5371
const int maxn=210001;
int s[maxn],a[maxn];
int r[maxn],len;

void Manancher()
{
    int l=0;
    a[l++]=-2;
    a[l++]=-1;
    for(int i=0;i<len;i++)
    {
        a[l++]=s[i];
        a[l++]=-1;
    }
    a[l]=-3;
    int mx=0,id=0;
    for(int i=0;i<l;i++)
    {
        r[i]=mx>i?min(r[2*id-i],mx-i):1;
        while(a[i+r[i]]==a[i-r[i]])r[i]++;
        if(i+r[i]>mx)
        {
            mx=i+r[i];
            id=i;
        }
        //printf("%d ",r[i]);
    }
    // printf("\n");
}

int main()
{
    int T,tt=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&len);
        for(int i=0;i<len;i++)
        {
            scanf("%d",&s[i]);
        }
        Manancher();
        int ans=0;
        for(int i=1;i<=len*2+1;i+=2)
        {
            for(int j=i+r[i]-1;j-i>ans;j-=2)
            {
                if(j-i+1<=r[j])
                {
                    ans=max(ans,j-i);
                    break;
                }
            }
        }
        printf("Case #%d: %d\n",++tt,ans/2*3);
    }
    return 0;
}

//hdu 4513 完美队列
const int oo=0x3f3f3f3f;
//const lld OO=1LL<<61;
const int MOD=10007;
const int maxn=200010;
int h[maxn],n,len;
int p[maxn];

int Manacher()
{
    int mx=0,id=0;
    for(int i=1;i<=len;i++)
    {
        if(mx>i)
            p[i]=min(mx-i,p[2*id-i]);
        else
            p[i]=1;
        while(h[i+p[i]]==h[i-p[i]]&&h[i-p[i]]<=h[i-p[i]+2])
            p[i]++;
        if(p[i]+i>mx)
        {
            mx=p[i]+i;
            id=i;
        }
    }
    int ans=0;
    for(int i=1;i<=len;i++)
        ans=max(ans,p[i]-1);
    return ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        len=0;
        h[len]=oo;
        for(int i=1;i<=n;i++)
        {
            h[++len]=-1;
            scanf("%d",&h[++len]);
        }
        h[++len]=-1;
        h[++len]=-oo;
        printf("%d\n",Manacher());
    }
    return 0;
}

//hust 1017 舞蹈链
const int oo=0x3f3f3f3f;
//const lld OO=1LL<<61;
const int MOD=10007;
const int maxn=200010;
int h[maxn],n,len;
int p[maxn];

int Manacher()
{
    int mx=0,id=0;
    for(int i=1;i<=len;i++)
    {
        if(mx>i)
            p[i]=min(mx-i,p[2*id-i]);
        else
            p[i]=1;
        while(h[i+p[i]]==h[i-p[i]]&&h[i-p[i]]<=h[i-p[i]+2])
            p[i]++;
        if(p[i]+i>mx)
        {
            mx=p[i]+i;
            id=i;
        }
    }
    int ans=0;
    for(int i=1;i<=len;i++)
        ans=max(ans,p[i]-1);
    return ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        len=0;
        h[len]=oo;
        for(int i=1;i<=n;i++)
        {
            h[++len]=-1;
            scanf("%d",&h[++len]);
        }
        h[++len]=-1;
        h[++len]=-oo;
        printf("%d\n",Manacher());
    }
    return 0;
}

//多重覆盖hdu2295
//二分答案, 然后使用重复覆盖的Dancing Links模板进行判断,看使用K个能不能覆盖n个点
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 60;
const int MAXM = 60;
const int MAXNODE = MAXN * MAXM;
const double eps = 1e-10;
int K;
struct DLX
{
    int n,m,sz;
    int U[MAXNODE],D[MAXNODE],R[MAXNODE],L[MAXNODE],Row[MAXNODE],Col[MAXNODE];
    int H[MAXN],S[MAXM];
    int ands,ans[MAXN];
    
    void init(int _n,int _m)
    {
        n = _n;
        m = _m;
        for(int i = 0;i <= m;i++)
        {
            S[i] = 0;
            U[i] = D[i] = i;
            L[i] = i-1;
            R[i] = i+1;
        }
        R[m] = 0; L[0] = m;
        sz = m;
        for(int i = 1 ; i <= n ; i++)
            H[i] = -1;
    }
    
    void Link(int r,int c)
    {
        ++S[Col[++sz] = c];
        Row[sz] = r;
        D[sz] = D[c];
        U[D[c]] = sz;
        U[sz] = c;
        D[c] = sz;
        if(H[r] < 0)H[r] = L[sz] = R[sz] = sz;
        else
        {
            R[sz] = R[H[r]];
            L[R[H[r]]] = sz;
            L[sz] = H[r];
            R[H[r]] = sz;
        }
    }
    
    void Remove(int c)
    {
        for(int i = D[c] ; i != c ; i = D[i])
            L[R[i]] = L[i], R[L[i]] = R[i];
    }
    
    void resume(int c)
    {
        for(int i = U[c] ; i != c ; i = U[i])
            L[R[i]] = R[L[i]] = i;
    }
    
    bool v[MAXNODE];
    int f()
    {
        int ret = 0;
        for(int c = R[0] ; c != 0 ; c = R[c])v[c] = true;
        for(int c = R[0] ; c != 0 ; c = R[c])
            if(v[c])
            {
                ret++;
                v[c] = false;
                for(int i = D[c] ;i != c ;i = D[i])
                    for(int j = R[i] ;j != i ; j = R[j])
                        v[Col[j]] = false;
            }
        return ret;
    }
    
    bool Dance(int d)
    {
        if(d + f() > K)return false;
        if(R[0] == 0)return d <= K;
        int c = R[0];
        for(int i = R[0];i != 0;i = R[i])
            if(S[i] < S[c])
                c = i;
        for(int i = D[c];i != c;i = D[i])
        {
            Remove(i);
            for(int j = R[i] ; j != i ; j = R[j])Remove(j);
            if(Dance(d + 1))return true;
            for(int j = L[i] ; j != i ; j = L[j])resume(j);
            resume(i);
        }
        return false;
    }
};

DLX slover;
struct point
{
    int x,y;
}city[MAXN],station[MAXN];

inline double dis(point a,point b)
{
    return sqrt(1.0 * (a.x - b.x) * (a.x - b.x) + 1.0 * (a.y - b.y) * (a.y - b.y));
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        int n,m;
        scanf("%d%d%d",&n,&m,&K);
        for (int i = 0 ; i < n ; i++)scanf("%d%d",&city[i].x,&city[i].y);
        for (int i = 0 ; i < m ; i++)scanf("%d%d",&station[i].x,&station[i].y);
        double l = 0,r = 1e8;
        while (r - l > eps)
        {
            double mid = l + (r - l) / 2;
            slover.init(m,n);
            for (int i = 0 ; i < m ; i++)
            {
                for (int j = 0 ; j < n ; j++)
                {
                    double dist = dis(station[i],city[j]);
                    if (dist < mid - eps)
                        slover.Link(i + 1,j + 1);
                }
            }
            if (slover.Dance(0)) r = mid - eps;
            else l = mid + eps;
        }
        printf("%.6lf\n",l);
    }
    return 0;
}
//FZU 1686 神龙的难题
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 250;
const int MAXM = 250;
const int MAXNODE = MAXN * MAXN;
const int INF = 0x3f3f3f3f;

struct DLX
{
    int n,m,sz;
    int U[MAXNODE],D[MAXNODE],R[MAXNODE],L[MAXNODE],Row[MAXNODE],Col[MAXNODE];
    int H[MAXN],S[MAXM];
    int ansd,ans[MAXN];
    
    void init(int _n,int _m)
    {
        n = _n;
        m = _m;
        for(int i = 0;i <= m;i++)
        {
            S[i] = 0;
            U[i] = D[i] = i;
            L[i] = i-1;
            R[i] = i+1;
        }
        R[m] = 0; L[0] = m;
        sz = m;
        for(int i = 1 ; i <= n ; i++)
            H[i] = -1;
    }
    
    void Link(int r,int c)
    {
        ++S[Col[++sz] = c];
        Row[sz] = r;
        D[sz] = D[c];
        U[D[c]] = sz;
        U[sz] = c;
        D[c] = sz;
        if(H[r] < 0)H[r] = L[sz] = R[sz] = sz;
        else
        {
            R[sz] = R[H[r]];
            L[R[H[r]]] = sz;
            L[sz] = H[r];
            R[H[r]] = sz;
        }
    }
    
    void Remove(int c)
    {
        for(int i = D[c] ; i != c ; i = D[i])
            L[R[i]] = L[i], R[L[i]] = R[i];
    }
    
    void resume(int c)
    {
        for(int i = U[c] ; i != c ; i = U[i])
            L[R[i]] = R[L[i]] = i;
    }
    
    bool v[MAXNODE];
    int f()
    {
        int ret = 0;
        for(int c = R[0] ; c != 0 ; c = R[c])v[c] = true;
        for(int c = R[0] ; c != 0 ; c = R[c])
            if(v[c])
            {
                ret++;
                v[c] = false;
                for(int i = D[c] ;i != c ;i = D[i])
                    for(int j = R[i] ;j != i ; j = R[j])
                        v[Col[j]] = false;
            }
        return ret;
    }
    
    void Dance(int d)
    {
        if(d + f() >= ansd)return;
        if(R[0] == 0)
        {
            ansd = min(ansd,d);
            return;
        }
        int c = R[0];
        for(int i = R[0];i != 0;i = R[i])
            if(S[i] < S[c])
                c = i;
        for(int i = D[c];i != c;i = D[i])
        {
            Remove(i);
            for(int j = R[i] ; j != i ; j = R[j])Remove(j);
            Dance(d + 1);
            for(int j = L[i] ; j != i ; j = L[j])resume(j);
            resume(i);
        }
        return;
    }
};

int id[30][30];
int N,M;
int ln,lm;
DLX slover;

int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
        int cas = 0;
        memset(id,0,sizeof(id));
        for (int i = 1 ; i <= N ; i++)
        {
            for (int j = 1 ; j <= M ; j++)
            {
                int x;
                scanf("%d",&x);
                if (x) id[i][j] = ++cas;
            }
        }
        scanf("%d%d",&ln,&lm);
        slover.init(N * M,cas);
        cas = 1;
        for (int i = 1 ; i <= N ; i++)
        {
            for (int j = 1 ; j <= M ; j++)
            {
                for (int stepx = 0 ; stepx < ln && i + stepx <= N ; stepx++)
                    for (int stepy = 0 ; stepy < lm && j + stepy <= M ; stepy++)
                    {
                        if (id[i + stepx][j + stepy])
                            slover.Link(cas,id[i + stepx][j + stepy]);
                    }
                cas++;
            }
        }
        slover.ansd = INF;
        slover.Dance(0);
        printf("%d\n",slover.ansd);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值