BZOJ2597 [Wc2007]剪刀石头布

什么鬼。。。冬令营题目不看题解能做?

(看了题解也不会2333)

其中有一部还是可以仔细思考一下的,就是对于费用流,如果每条边边满足:cost = a * flow2,如何做?

我们可以拆边,新边上,每条边流量为1,费用为a * (x2 - (x - 1)2)(就是费用为a * (12 - 02), a * (22 - 12)...)

拆边的思想还是很广泛的,恩...!

 

  1 /**************************************************************
  2     Problem: 2597
  3     User: rausen
  4     Language: C++
  5     Result: Accepted
  6     Time:11144 ms
  7     Memory:10756 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio>
 11 #include <cstring>
 12 #include <algorithm>
 13  
 14 using namespace std;
 15 const int Num = 105;
 16 const int N = Num * Num;
 17 const int M = 500005;
 18 const int inf = (int) 1e9;
 19  
 20 struct edges {
 21     int next, to, f, cost;
 22     edges() {}
 23     edges(int _n, int _t, int _f, int _c) : next(_n), to(_t), f(_f), cost(_c) {}
 24 } e[M];
 25   
 26 int tot = 1, first[N];
 27 int n, m, S, T;
 28 int in[Num], d[N], q[N], g[N];
 29 int sum[M];
 30 bool v[N];
 31  
 32 inline int read() {
 33     int x = 0;
 34     char ch = getchar();
 35     while (ch < '0' || '9' < ch)
 36         ch = getchar();
 37     while ('0' <= ch && ch <= '9') {
 38         x = x * 10 + ch - '0';
 39         ch = getchar();
 40     }
 41     return x;
 42 }
 43  
 44 inline void Add_Edges(int x, int y, int f, int c) {
 45     e[++tot] = edges(first[x], y, f, c), first[x] = tot;
 46     e[++tot] = edges(first[y], x, 0, -c), first[y] = tot;
 47 }
 48   
 49 inline int calc() {
 50     int flow = inf, x;
 51     for (x = g[T]; x; x = g[e[x ^ 1].to])
 52         flow = min(flow, e[x].f);
 53     for (x = g[T]; x; x = g[e[x ^ 1].to])
 54         e[x].f -= flow, e[x ^ 1].f += flow;
 55     return flow;
 56 }
 57   
 58 bool spfa() {
 59     int x, y, l, r;
 60     for (x = 1; x <= T; ++x)
 61         d[x] = inf;
 62     d[S] = 0, v[S] = 1, q[0] = S;
 63     for(l = r = 0; l != (r + 1) % N; ++l %= N) {
 64         for (x = first[q[l]]; x; x = e[x].next)
 65             if (d[q[l]] + e[x].cost < d[y = e[x].to] && e[x].f) {
 66                 d[y] = d[q[l]] + e[x].cost, g[y] = x;
 67                 if (!v[y])
 68                     q[++r %= N] = y, v[y] = 1;
 69             }
 70         v[q[l]] = 0;
 71     }
 72     return d[T] != inf;
 73 }
 74  
 75 inline int work() {
 76     int res = 0;
 77     while (spfa())
 78         res += calc() * d[T];
 79     return res;
 80 }
 81  
 82 void build_graph() {
 83     int i, j, x, now = 0;
 84     for (i = 1; i <= n; ++i)
 85         for (j = 1; j <= n; ++j) {
 86             x = read();
 87             if (j <= i) continue;
 88             sum[++now] = i + j;
 89             if (x == 2) {
 90                 Add_Edges(now, i + m, 1, 0), Add_Edges(now, j + m, 1, 0);
 91                 ++in[i], ++in[j];
 92             } else
 93             if (x == 1) Add_Edges(now, i + m, 1, 0), ++in[i];
 94             else Add_Edges(now, j + m, 1, 0), ++in[j];
 95         }
 96     for (i = 1; i <= m; ++i)
 97         Add_Edges(S, i, 1, 0);
 98     for (i = 1; i <= n; ++i)
 99         for (j = 1; j <= in[i]; ++j)
100             Add_Edges(i + m, T, 1, 2 * j - 1);
101 }
102  
103 void make_ans() {
104     int a[Num][Num], i, j, x;
105     memset(a, 0, sizeof(a));
106     for (i = 1; i <= m; ++i)
107         for (x = first[i]; x; x = e[x].next)
108             if (!e[x].f) a[e[x].to - m][sum[i] - e[x].to + m] = 1;
109     for (i = 1; i <= n; ++i) {
110         for (j = 1; j <= n; ++j)
111             printf("%d ", a[i][j]);
112         printf("\n");
113     }
114 }
115  
116 int main() {
117     n = read(), m = n * (n - 1) / 2;
118     S = n + m + 1, T = S + 1;
119     build_graph();
120     printf("%d\n", (n * (n - 1) * (n - 2) / 3 + m - work()) / 2);
121     make_ans();
122     return 0;
123 }
View Code

(p.s.  为何这么慢= =我去。。)

转载于:https://www.cnblogs.com/rausen/p/4197953.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值