最小割模型(hdu5076 2014鞍山)

Memory

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 279    Accepted Submission(s): 59
Special Judge


Problem Description
Little Bob’s computer has 2 n bytes of memory. For convenience, n-bit integers 0 to 2 n - 1 are used to index these bytes.



Now he wants to assign a value to each byte of the memory. In this problem, a byte is composed of m bits. Therefore he can only assign 0 to 2 m - 1 (inclusive) to a single byte.

Bob has some preferences on which value to be assigned to each byte. For the byte indexed by i, if it is assigned with value j (0 ≤ j < 2 m), the preference score for it is w i, j.

In addition, each byte has a threshold value. For two different bytes indexed by a and b, if the following two conditions are satisfied, there will be an additional score (u a xor u b):

1.a and b only have one bit of difference in their binary forms;

2.The assigned value of byte a is not less than its threshold value, or the assigned value of byte b is not less than its threshold value.

The total score of an assignment solution is the sum of the preference scores of all bytes plus the sum of all additional scores.

Bob wants to find an assignment solution with the maximum total score. If there are multiple solutions, you can output any of them.
 

Input
The first line contains an integer T (T ≤ 3), denoting the number of the test cases.

For each test case, the first line contains two integers, n and m(1 ≤ n, m ≤ 8), as mentioned above. The second line contains 2 n integers, and the i-th integer is the threshold value for byte i. The threshold values are between 0 and 2 m - 1, inclusively. The third line contains 2 n integers, and the i-th integer is ui(0 ≤ u i < 1024). The next 2 n lines give all preference scores. Each line contains 2 m integers, and the j-th integer of the i-th line is w i, j (-1024 ≤ w i, j < 1024).
 

Output
For each test case, output one line consisting of 2 n integers between 0 and 2 m - 1, and the i-th integer is the value assigned to byte i in the assignment solution with the maximum total score.
 

Sample Input
  
  
1 3 2 0 1 1 3 3 0 3 3 4 8 8 7 0 9 2 9 -9 -8 3 2 -9 -6 4 1 -6 -8 -5 3 3 -1 -4 -1 -6 -5 1 10 -10 7 3 -10 -3 -10 -4 -5 -2 -1 -9 1
 

Sample Output
  
  
2 2 3 0 3 1 0 3
 

2n 个内存位,每个位置可以放一个数字,范围为 [0,2m) ,第 i 个位置放 j 可以得到 w(i,j) 的收益,每个位置还有一个临界值 ti 以及一个 ui

除此之外,一旦有两个位置 a,b 满足以下两个条件,可额外获得 ua  xor  ub 的收益。

  • a b 在二进制下只有一个bit不同。
  • a 位置放的数不小于 ta 或者 b 位置放的数不小于 tb

求最大收益的一组方案。

如果不考虑额外收益,显然每个位置 i 放的都是使得 w(i,j) 最大的 j 。而考虑额外收益后,需要分两种情况,放的数小于等于 ti 以及大于 ti 。每种情况保留下来的一样都是使得 w(i,j) 最大的 j

由题意知,对于每一组满足条件一的 a,b ,只有两个位置都小于 ta,tb 时才获得不到收益。从这里就能大概看出一个最小割模型了,割就是要抛弃的收益。

对于比较常见的模型一般都是一个二分图,而这题看起来“选择同侧”的点有额外代价的条件似乎很迷惑人,但注意到第一个条件,就可以发现可以利用二进制1的个数的奇偶性来让模型变成”选择异侧”的点有额外代价。

最后的建模过程就很好理解了。

  • 对于每个位置拆成两个点,左边源右边汇。
  • 如果这个位置的index有奇数个1,左边连小于的 w ,右边连大于等于的 w
  • 如果这个位置的index有偶数个1,左边连大于等于的 w ,右边连小于的 w
  • 每个位置左边往右边连一条inf的弧,代表这两个点不能都不割。
  • 对于每组 a,b ,从奇数的小于连向偶数的小于, ua  xor  ub
  • 为了避免负流量可以把所有w加一个1024,不影响最后结果。
  • 总之建出来是个二分图。
  • 最后建完就可以发现其实可以不用拆点,但拆了还是更好理解一些。

最后所有的收益加起来减掉最小割就是最大收益。

上面是官方题解:下面的题解是参考网上的,不需要拆点的,思路跟上面应该是一样的

对于奇数点,在他与原点之间加一条权值为,大于t的最大值的w,汇点加小于t的最大的w,偶数点相犯,对于只差一位的,偶数点->奇数点加一条异或的边

求最大流之后用总的减去。

其实还是相当于把两个差一位的,并且值都小于t的流量减掉,以免,小于t的w大于,大于t的w+额外的效益,因为相同情况下肯定是加w大的核算,所以只需要选择大的就可以了,然后排除掉上面的情况

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=256*256+10;
const int maxm=300;
int N,M;
int t[maxm],u[maxm];
int w[maxm][maxm];
int t1[maxm],t2[maxm],b[maxm];
int a[maxm],digit[maxm],head[maxm];
int st,en,tot,nn,cur[maxm];
int dis[maxm],gap[maxm],vis[maxm],pre[maxm];
struct node
{
    int u,v,f,next;
}edge[maxn];
void add_edge(int x,int y,int f)
{
    edge[tot].u=x;
    edge[tot].v=y;
    edge[tot].f=f;
    edge[tot].next=head[x];
    head[x]=tot++;
    edge[tot].u=y;
    edge[tot].v=x;
    edge[tot].f=0;
    edge[tot].next=head[y];
    head[y]=tot++;
}
int SAP(int st,int en)
{
    for(int i=0;i<=nn;i++)
    {
        cur[i]=head[i];
        dis[i]=gap[i]=0;
    }
    int u=0;
    int flow=0,aug=INF;
    gap[st]=nn;
    u=pre[st]=st;
    bool flag;
    while(dis[st]<nn)
    {
        flag=0;
        for(int &j=cur[u];j!=-1;j=edge[j].next)
        {
            int v=edge[j].v;
            if(edge[j].f>0&&dis[u]==dis[v]+1)
            {
                flag=1;
                if(edge[j].f<aug)aug=edge[j].f;
                pre[v]=u;
                u=v;
                if(u==en)
                {
                    flow+=aug;
                    while(u!=st)
                    {
                        u=pre[u];
                        edge[cur[u]].f-=aug;
                        edge[cur[u]^1].f+=aug;
                    }
                    aug=INF;
                }
                break;
            }
        }

        if(flag)continue;
        int mindis=nn;
        for(int j=head[u];j!=-1;j=edge[j].next)
        {
            int v=edge[j].v;
            if(dis[v]<mindis&&edge[j].f>0)
            {
                mindis=dis[v];
                cur[u]=j;
            }
        }
        if((--gap[dis[u]])==0)break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return flow;
}
void dfs(int u)
{
    vis[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(vis[v])continue;
        if(edge[i].f>0)
            dfs(v);

    }
}
int choice[maxm];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&M);
        for(int i=0;i<(1<<N);i++)scanf("%d",&t[i]);
        for(int i=0;i<(1<<N);i++)scanf("%d",&u[i]);
        for(int i=0;i<(1<<N);i++)
            for(int j=0;j<(1<<M);j++)
                scanf("%d",&w[i][j]),w[i][j]+=1024;
        for(int i=0;i<(1<<N);i++)
        {
            t1[i]=t2[i]=-1;
            a[i]=b[i]=-INF;
            for(int k=t[i];k<(1<<M);k++)
                if(w[i][k]>a[i])
                {
                    a[i]=w[i][k];
                    t1[i]=k;
                }
            for(int k=0;k<t[i];k++)
            {
                if(w[i][k]>b[i])
                {
                    b[i]=w[i][k];
                    t2[i]=k;
                }
            }
        }
        memset(head,-1,sizeof(head));
        tot=0;
        st=(1<<N);en=st+1,nn=en+1;
        int ans=0;
        for(int i=0;i<(1<<N);i++)
        {
            int cnt=0;
            for(int j=0;j<N;j++)
                if(i&(1<<j))cnt++;
            if(cnt%2)
            {
                add_edge(st,i,a[i]);
                if(b[i]>=0)add_edge(i,en,b[i]);
            }
            else
            {
                if(b[i]>=0)add_edge(st,i,b[i]);
                add_edge(i,en,a[i]);
            }
            digit[i]=cnt;
            ans+=a[i];
            if(b[i]>=0)ans+=b[i];
        }
        for(int i=0;i<(1<<N);i++)
            for(int j=0;j<(1<<N);j++)
                if((digit[j]%2)&&(!(digit[i]%2))&&(digit[i^j])==1)
                add_edge(i,j,u[i]^u[j]),ans+=u[i]^u[j];
        int res=ans-SAP(st,en)-(1<<N)*1024;
        memset(vis,0,sizeof(vis));
        dfs(st);
        for(int i=0;i<(1<<N);i++)
        {
            if(vis[i])choice[i]=(((digit[i]&1)==1) ? t1[i] : t2[i]) ;
            else choice[i]=(((digit[i]&1)==1) ? t2[i] : t1[i] );
            printf("%d",choice[i]);
            if(i==(1<<N)-1)printf("\n");
            else printf(" ");
        }
    }
    return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值