spoj AMR11 Robbing Gringotts 双边暴力+hash+费用流

   开始的时候,明显背包的复杂度是10000000*25*50 然后认为暴力的复杂度(1<<25)*50 还小于前者,然后就是各种剪纸,然后就是各种tle ,后面看题解又是暴力一半,hash一半,复杂度可以为(sqrt(1<<25)*50),可见解,然后就是一遍费用流,有km也可以吧,但是只会费用流,模板上,如果不懂暴力一半hash 一半的请看zoj3661,

#include<cstdio>
#include<cstring>
#define M 60
#define N   200000
#define mod 133331
int n,m;
int a[M][M];
int map1[M][M];
struct H{
    int head[N],en;
    struct E{
        int u,v,next;
    }e[N<<2];
    void init(){
        memset(head,-1,sizeof(head));en=0;
    }
    int change(int x){
        return x%mod;
    }
    void add(int x){
        int t1=change(x);
        e[en].u=t1;e[en].v=x;e[en].next=head[t1];head[t1]=en++;
    }
    int find(int x){
        int t1=change(x);
        for(int i=head[t1];~i;i=e[i].next){
            if(e[i].v==x) return 1;
        }
        return 0;
    }
}hash;
int b[M];
int ans[N],en;
int tmax;
void dfs1(int id,int level,int tsum){
    if(level==a[id][0]/2+1){
        ans[en++]=tsum;
        return ;
    }
    dfs1(id,level+1,tsum+a[id][level]);
    dfs1(id,level+1,tsum);
}
void dfs2(int id,int level,int tsum){
    if(level==a[id][0]+1){
        hash.add(tsum);
        return ;
    }
    dfs2(id,level+1,tsum+a[id][level]);
    dfs2(id,level+1,tsum);
}
void work1(){
    for(int i=0;i<m;i++){
        hash.init();
        en=0;
        dfs1(i,1,0);
        dfs2(i,a[i][0]/2+1,0);
        for(int j=0;j<n;j++){
            int t1=b[j];
            for(int k=0;k<en;k++){
                int t2=ans[k];
                if(t2>t1) continue;
                int t3=t1-t2;
                if(hash.find(t3)){
                   map1[i][j]=1;
                   break;
                }
            }
        }
    }
}
#define inf 0x3f3f3f3f
using namespace std;
/*
sumflow is max_flow
*/
const int MAXN=200;
const int MAXM=10000;
const int INF=inf;
int sumflow;
struct Edge
{
    int u,v,cap,cost,ednxt;
}edge[MAXM<<2];
int edn,head[MAXN],dist[MAXN],pp[MAXN];
bool vis[MAXN];
void init()
{
    edn=0,memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int cap,int cost)
{
    edge[edn].u=u,edge[edn].v=v,edge[edn].cap=cap,edge[edn].cost=cost, edge[edn].ednxt=head[u],head[u]=edn++;
    edge[edn].u=v,edge[edn].v=u,edge[edn].cap=0,  edge[edn].cost=-cost,edge[edn].ednxt=head[v],head[v]=edn++;
}
int my_queue[MAXN<<3];
int tp,hp;
bool spfa(int s,int t,int n)
{
    int i,u,v;
    hp=0;tp=-1;
    memset(vis,false,sizeof(vis));
    memset(pp,-1,sizeof(pp));
    for(i=0;i<=n;i++) dist[i]=INF;
    vis[s]=true,dist[s]=0;
    my_queue[++tp]=s;
    while(tp>=hp)
    {
        u=my_queue[tp--];vis[u]=false;
        for(i=head[u];i!=-1;i=edge[i].ednxt)
        {
            v=edge[i].v;
            if(edge[i].cap&&dist[v]>dist[u]+edge[i].cost)
            {
                dist[v]=dist[u]+edge[i].cost;
                pp[v]=i;
                if(!vis[v])
                {
                    my_queue[++tp]=v;
                    vis[v]=true;
                }
            }
        }
    }
    if(dist[t]==INF)return false;
    return true ;
}
int mcmf(int s,int t,int n)
{
    int flow=0;
    int i,minflow,mincost;
    mincost=0;
    while(spfa(s,t,n))
    {
        minflow=INF+1;
        for(i=pp[t];i!=-1;i=pp[edge[i].u])
            if(edge[i].cap<minflow)
                minflow=edge[i].cap;
        flow+=minflow;
        for(i=pp[t];i!=-1;i=pp[edge[i].u])
        {
            edge[i].cap-=minflow;
            edge[i^1].cap+=minflow;
        }
        mincost+=dist[t]*minflow;
    }
    sumflow=flow;
    return mincost;
}
int build(int n,int m){
    int sp=0;tp=n+m+1;
    init();
    for(int i=1;i<=n;i++){
        addedge(sp,i,1,0);
    }
    for(int i=1;i<=m;i++){
        addedge(i+n,tp,1,0);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(map1[j-1][i-1]==1){
                addedge(i,j+n,1,-b[i-1]);
            }
        }
    }
    int ans=mcmf(sp,tp,tp+2);
    return -ans;
}
int main(){
    int cas;while(~scanf("%d",&cas)){
        while(cas--){
            scanf("%d%d",&n,&m);
            for(int i=0;i<n;i++) scanf("%d",&b[i]);
            for(int i=0;i<m;i++){
                scanf("%d",&a[i][0]);
                for(int j=1;j<=a[i][0];j++){
                    scanf("%d",&a[i][j]);
                }
            }
            memset(map1,0,sizeof(map1));
            work1();
            int ans=build(n,m);//建图
            printf("%d\n",ans);
        }
    }
    return 0;
}
/*
100
4 4

3 7 8 10

3 1 2 4

2 3 7

4 0 0 0 0

1 1
*/

时间好像排到到前几吧,ye

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值