bzoj2400 Spoj 839 Optimal Marks


题目链接

思路

既然是异或预算,很容易想到按位操作。
按位操作之后,每个点的权值就只有\(0\)\(1\)两个了,然后从\(S\)向所有权值为\(0\)的点连一条\(INF\)的边,从所有权值为\(1\)的点向\(T\)连一条\(INF\)的边。然后将原图中的边全都连成权值为\(1\)的边。然后求最小割。
如果没有不确定的点权,那么很明显这样是对的。
画出图来就可以知道,对于不确定的点权这样操作也是对的。
这样就可以完成第一问了。
然后考虑第二问。在满足最小割的情况下要求点权最小。也就是说。再使得最小割不变的情况下,每个点的权值尽量的为\(0\),也就是说尽量的割掉与\(T\)的连边。这样就有一个非常神奇的做法。
将原图中的边不再连\(1\),而是连成\(10000\).然后从\(S\)向每个点连一条权值为\(1\)的边。画出图来就可以发现这样是对的。
因为如果当前割掉与\(S\)的连边和割掉与\(T\)的连边同样优秀的话,如果割掉了与\(S\)的连边,那么还有一条与\(S\)相连为\(1\)的边。使得还有\(1\)的流量,肯定会不优秀。所以这种情况就会优先割掉与T的连边。

代码

/*
* @Author: wxyww
* @Date:   2019-02-09 11:35:38
* @Last Modified time: 2019-02-10 07:53:05
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstring>
#include<bitset>
using namespace std;
typedef long long ll;
#define int ll
const int N = 2010,INF = 1e9;
ll read() {
    ll x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}
struct node {
    int v,nxt,w,u;
}e[N * 10];
int head[N],ejs;
void add(int u,int v,int w) {
    e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w;
    e[++ejs].v = u;e[ejs].nxt = head[v];head[v] = ejs;e[ejs].w = 0;
}
int n,m,w[N],U[N],V[N];
int dep[N],S,T;
queue<int>q;
int bfs() {
    memset(dep,0,sizeof(dep));
    while(!q.empty()) q.pop();
    dep[S] = 1;
    q.push(S);
    while(!q.empty()) {
        int u = q.front();q.pop();
        for(int i = head[u];i;i = e[i].nxt) {
            int v = e[i].v;
            if(!dep[v] && e[i].w) {
                dep[v] = dep[u] + 1;
                q.push(v);
                if(v == T) return 1;
            }
        }
    }
    return 0;
}
int dfs(int u,int now) {
    if(u == T) return now;
    int ret = 0;
    for(int i = head[u];i;i = e[i].nxt) {
        int v = e[i].v;
        if(e[i].w && dep[v] == dep[u] + 1) {
            int k = dfs(v,min(now - ret,e[i].w));
            e[i].w -= k;
            e[i ^ 1].w += k;
            ret += k;
            if(ret == now) return now;
        }
    }
    return ret;
}
int dinic() {
    int ans = 0;
    while(bfs()) ans += dfs(S,INF); 
    return ans;
}
void build(int x) {
    ejs = 1;
    memset(head,0,sizeof(head));
    for(int i = 1;i <= n;++i) {
        if(w[i] >= 0) {
            if(w[i] & x) add(i,T,INF),add(S,i,1);
            else add(S,i,INF);
        }
        else add(S,i,1);
    }
    for(int i = 1;i <= m;++i) {
        add(U[i],V[i],10000);add(V[i],U[i],10000);
    }
}
signed main() {
    n = read();m = read();
    S = n + 1,T = S + 1;
    for(int i = 1;i <= n;++i) w[i] = read();
    for(int i = 1;i <= m;++i) U[i] = read(),V[i] = read();
    int ans1 = 0,ans2 = 0;
    for(int i = 0;i <= 31;++i) {
        build(1 << i);
        int K = dinic();
        ans1 += K / 10000 * (1 << i);
        ans2 += K % 10000 * (1 << i);
    }
    printf("%lld\n%lld\n",ans1,ans2);
    return 0;
}
全部评论

相关推荐

昨天 11:04
已编辑
北方民族大学 全栈开发
“无名小卒还是名扬天下?”我知道很多人都不觉得我能走到今天这一步,当然,也包括我自己。在我的人生里,有两部作品刻下了最深的印记:《斗破苍穹》与《龙族》。这两部书总被人拿来对照:一边是萧炎的桀骜轻狂,一边是路明非的怯懦衰颓。有人说,天蚕土豆没见过魂天帝,但江南见过真凯撒。我时常觉得自己就是那个衰小孩路明非,可路明非可以开挂,我不可以;我也无数次幻想过能拥有萧炎那般年少轻狂的人生,可我没有他与生俱来的逆天天赋。我只是个平庸的普通人,一个看过《斗破苍穹》却开不了挂的路明非,只能一步一步往上爬。从我下定决心找实习的那一刻起,我就给自己定下了目标:我一定要为字节跳动卖命.jpg。萧炎有他的三年之约,我有我的两年半之约(其实是一年半)。2024.11.20,科大讯飞的第一封实习offer落进邮箱,我迈出了这场奔赴的第一步。2025.8.18,放弃百度转正的安稳机会,转身走进前路未卜的不确定里。我很感谢我在百度的mentor,是她从茫茫人海选中了我,给了我大厂实习的机会。即便那段时间我状态差、产出不理想,她依旧愿意认可我、希望我留下转正。2025.11.14,我选择走进字节跳动,以实习生的身份重新出发,放下过往,清零重来,只为奔赴心之所向。2026.3.25&nbsp;-&nbsp;3.27,三天速通上海飞书,斩获Special&nbsp;Offer。被告知面试通过的那一刻,我的内心无比平静,就像这个offer本就该属于我。不是侥幸,是应得的。这一路,有人看轻过我的出身,不相信我能走到这里;也有人在我看不见前路的时候,替我举过灯。没有他们的鼓励与支撑,就没有今天站在这里的我。我看到了自强不息的激荡,那是一个双非的伟大乐章!我是雨夜迈巴赫,我要开启属于我的新篇章了。
在看牛客的本杰明很勇...:真心祝贺l总 我永远的偶像 我滴神
春招至今,你收到几个面试...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务