[hdu4888]最大流,判断最大流唯一性

题意:给一个n*m的矩形,往每个格子填0-k的数字,使得对第i行和为row[i],第i列和为col[i],问是否存在方案,方案是否唯一,如果方案唯一则输出具体方案。

思路:首先根据问题提取对象,行、列、格子、数,只有数可以连接其它的对象。从源点向第i行连一条容量为row[i]的有向边,从第i行向第i行的每个格子连一条容量为k的有向边,从每个格子向第i列(i为格子的列号)连一条容量为k的有向边,然后从第i列向汇点连一条容量为col[i]的边。这样建图以后,发现每个格子唯一连接一个行和一个列,也就是入度和出度均为1,那么格子其实就没有存在的必要了,直接从每行向每列连一条容量为k的有向边。如果最大流=Σrow[i]=Σcol[i],则表明有解。对于有多解的情况,只需判断残量网络是否存在有向环,因为在环上增减流量能得到不同的解而最大流不变。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

/* ******************************************************************************** */

#include <iostream>                                                                 //

#include <cstdio>                                                                   //

#include <cmath>                                                                    //

#include <cstdlib>                                                                  //

#include <cstring>                                                                  //

#include <vector>                                                                   //

#include <ctime>                                                                    //

#include <deque>                                                                    //

#include <queue>                                                                    //

#include <algorithm>                                                                //

#include <map>                                                                      //

using namespace std;                                                                //

                                                                                    //

#define pb push_back                                                                //

#define mp make_pair                                                                //

#define X first                                                                     //

#define Y second                                                                    //

#define all(a) (a).begin(), (a).end()                                               //

#define foreach(a, i) for (typeof(a.begin()) i = a.begin(); i != a.end(); ++ i)     //

#define fill(a, x) memset(a, x, sizeof(a))                                          //

                                                                                    //

void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);}    //

void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R>                    //

void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1;          //

while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T>      //

void print(const T t){cout<<t<<endl;}template<typename F,typename...R>              //

void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T>   //

void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}   //

                                                                                    //

typedef pair<intint> pii;                                                         //

typedef long long ll;                                                               //

typedef unsigned long long ull;                                                     //

                                                                                    //

template<typename T>bool umax(T&a, const T&b){return b>a?false:(a=b,true);}         //

template<typename T>bool umin(T&a, const T&b){return b<a?false:(a=b,true);}         //

template<typename T>                                                                //

void V2A(T a[],const vector<T>&b){for(int i=0;i<b.size();i++)a[i]=b[i];}            //

template<typename T>                                                                //

void A2V(vector<T>&a,const T b[]){for(int i=0;i<a.size();i++)a[i]=b[i];}            //

                                                                                    //

/* -------------------------------------------------------------------------------- */

struct Dinic {

private:

    const static int maxn = 800 + 7;

    struct Edge {

        int from, to, cap;

        Edge(int u, int v, int w): from(u), to(v), cap(w) {}

    };

    int s, t;

    vector<Edge> edges;

    vector<int> G[maxn];

    bool vis[maxn];

    int d[maxn], cur[maxn];

    bool bfs() {

        memset(vis, 0, sizeof(vis));

        queue<int> Q;

        Q.push(s);

        d[s] = 0;

        vis[s] = true;

        while (!Q.empty()) {

            int x = Q.front(); Q.pop();

            for (int i = 0; i < G[x].size(); i ++) {

                Edge &e = edges[G[x][i]];

                if (!vis[e.to] && e.cap) {

                    vis[e.to] = true;

                    d[e.to] = d[x] + 1;

                    Q.push(e.to);

                }

            }

        }

        return vis[t];

    }

    int dfs(int x, int a) {

        if (x == t || a == 0) return a;

        int flow = 0, f;

        for (int &i = cur[x]; i < G[x].size(); i ++) {

            Edge &e = edges[G[x][i]];

            if (d[x] + 1 == d[e.to] && (f = dfs(e.to, min(a, e.cap))) > 0) {

                e.cap -= f;

                edges[G[x][i] ^ 1].cap += f;

                flow += f;

                a -= f;

                if (a == 0) break;

            }

        }

        return flow;

    }

public:

    void clear() {

        for (int i = 0; i < maxn; i ++) G[i].clear();

        edges.clear();

        memset(d, 0, sizeof(d));

    }

    void add(int from, int to, int cap) {

        edges.push_back(Edge(from, to, cap));

        edges.push_back(Edge(to, from, 0));

        int m = edges.size();

        G[from].push_back(m - 2);

        G[to].push_back(m - 1);

    }

    int solve(int s, int t) {

        this->s = s; this->t = t;

        int flow = 0;

        while (bfs()) {

            memset(cur, 0, sizeof(cur));

            flow += dfs(s, 1e9);

        }

        return flow;

    }

    bool FC(int fa, int rt) {

        vis[rt] = true;

        int sz = G[rt].size();

        for (int i = 0; i < sz; i ++) {

            Edge &e = edges[G[rt][i]];

            if (e.to != fa && e.cap) {

                if (vis[e.to]) return true;

                if (FC(rt, e.to)) return true;

            }

        }

        vis[rt] = false;

        return false;

    }

    bool get(int n, int m) {

        memset(vis, 0, sizeof(vis));

        for (int i = 1; i <= n; i ++) {

            if (FC(-1, i)) return true;

        }

        return false;

    }

    void out(int n, int m) {

        int now = n * 2 + m * 2 + 1;

        for (int i = 0; i < n; i ++) {

            for (int j = 0; j < m; j ++) {

                printf("%d%c", edges[now].cap, j == m - 1? ‘\n‘ ‘ ‘);

                now += 2;

            }

        }

    }

};

Dinic solver;

const int maxn = 407;

int row[maxn], col[maxn];

int main() {

#ifndef ONLINE_JUDGE

    freopen("in.txt""r", stdin);

#endif // ONLINE_JUDGE

    int n, m, k;

    while (cin >> n >> m >> k) {

        solver.clear();

        int total = 0;

        for (int i = 1; i <= n; i ++) {

            int x;

            RI(x);

            solver.add(0, i, x);

            total += x;

        }

        for (int i = 1; i <= m; i ++) {

            int x;

            RI(x);

            solver.add(n + i, n + m + 1, x);

        }

        for (int i = 1; i <= n; i ++) {

            for (int j = 1; j <= m; j ++) {

                solver.add(i, n + j, k);

            }

        }

        int flow = solver.solve(0, n + m + 1);

        if (flow != total) puts("Impossible");

        else {

            if (solver.get(n, m)) puts("Not Unique");

            else {

                puts("Unique");

                solver.out(n, m);

            }

        }

    }

    return 0;                                                                       //

}                                                                                   //

                                                                                    //

                                                                                    //

                                                                                    //

/* ******************************************************************************** */

时间: 2024-11-09 00:53:53

[hdu4888]最大流,判断最大流唯一性的相关文章

hdu3572 任务分配/最大流判断满流

题意:将n个任务分配为m个机器,给每个任务需要的天数(无需每天连续),和可以在哪些天去做该任务,求是否存在方案. 典型的任务(X)----天(Y)二分最大流,(因为这里任务是与天的关系)处理器控制流量,源点向X部点,指需要的天数,任务xi,向可以做的天连,流量1,每个Y部点向汇点连流量为m,表示该天最多用M个机器. ps:注意输出格式 #include<iostream> #include<queue> #include<cstdio> #include<cstr

HDU 3572 Task Schedule(最大流判断满流)

https://vjudge.net/problem/HDU-3572 题意: 有N个作业和M台机器,每个作业都有一个持续时间P,工作的日期为S~E.作业可以断断续续的在不同机器上做,每台机器每次只可以处理一个作业.判断是否可以在作业的工作日期内完成所有作业. 思路: 建立源点0和汇点t,因为天数最多为500,所有我们将日期的编号定为1~500,作业的编号为500+i. 对于每个作业,与源点0相连,容量为P,意味着它必须走完这P容量才能完成这作业.与S~E相连,容量为1.日期与汇点相连,容量为m

hdu-3572 Task Schedule---最大流判断满流+dinic算法

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3572 题目大意: 给N个任务,M台机器.每个任务有最早才能开始做的时间S,deadline E,和持续工作的时间P.每个任务可以分段进行,但是在同一时刻,一台机器最多只能执行一个任务. 问存不存在可行的工作时间. 解题思路: 由于时间<=500且每个任务都能断断续续的执行,那么我们把每一天时间作为一个节点来用网络流解决该题. 建图: 源点s(编号0), 时间1-500天编号为1到500, N个任务

hdu4888 多校B 最大流以及最大流唯一判断+输出方案

题意,给一个矩阵,告诉你每行和.每列和,并且限制所填数不大于k,问矩阵是否唯一. 经典建图不说了,第一次遇到判断最大流唯一性的,学习了:用dfs来判断残网中是否还存在环,若存在,则表明绕这个环走一圈,(流一圈流量),还是最大流保持不变,说明还有解.输出方案就EASY了. WA了一天:第一TLE,因为这题卡DINIC,我的没有优化,后来在zz1215学长加了一行代码,在增广的时候,若发现最小总流量已经为0,则标记该点层-1(不必要往下).效果显著.原因2:判断环的时候,dfs判断环写错有木有!不可

hdu4888 Redraw Beautiful Drawings 最大流+判环

hdu4888 Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2007    Accepted Submission(s): 447 Problem Description Alice and Bob are playing together. Alice is crazy abou

hdu3572Task Schedule 最大流,判断满流 优化的SAP算法

PS:多校联赛的题目质量还是挺高的.建图不会啊,看了题解才会的. 参考博客:http://blog.csdn.net/luyuncheng/article/details/7944417 看了上面博客里的题解,思路就有了.不过建图还是有点麻烦.我把源点设为n+1 (不想从0开始,不修改模版),汇点就是n+2+MAX,其中MAX是题目中Ei的最大值. 这题,我有疑问:优化过的SAP算法的时间复杂度是O(m*n^2),此题的n最大为1000,m为50万,时间超过5亿了.1s的时限居然过了. 其中有个

HDU Redraw Beautiful Drawings 判断最大流是否唯一解

点击打开链接 Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1660    Accepted Submission(s): 357 Problem Description Alice and Bob are playing together. Alice is crazy about

hdu 4940 Destroy Transportation system( 无源汇上下界网络流的可行流判断 )

题意:有n个点和m条有向边构成的网络,每条边有两个花费: d:毁坏这条边的花费 b:重建一条双向边的花费 寻找这样两个点集,使得点集s到点集t满足 毁坏所有S到T的路径的费用和 > 毁坏所有T到S的路径的费用和 + 重建这些T到S的双向路径的费用和. 思路1: 然后这个无源汇带上下界网络流的可行流问题的求解方法见这里~~ 建图就是上面说的那样啦~最后判断有没有可行流就是求一下我们所构造的这个新的网络的最大流~然后判断一下这个最大流是否满流~(即判断最大流是否和附加源点的流出总量相等~~) cod

最大流判断方程是否有解

Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 3813 Accepted Submission(s): 1140 Problem DescriptionAlice and Bob are playing together. Alice is crazy about art and she h

产品三俗:瀑布流、动态流、奖章

有三种流行的产品要素“瀑布流.动态流.奖章”,我称之为产品三俗,容易因其流行而被滥用.PM选择它们有可能是因为“时髦”“标配”“别人都在用”,这很糟糕.恰好动态流和奖章我都折腾过,多多少少吃过一点亏,总结如下.云鼎娱乐城 瀑布流 瀑布流的鼻祖是Pinterest,Pinterest的用户97.9%是女性.有种说法是,洋妞们从小就有收集剪报的习惯,Pinterest将这个习惯移植到了网络上,故快速引爆流行.听上去挺有道理. 从交互角度来分析,瀑布流最大的好处有两个,第一是提高了“发现好图”的效率,