HDU4975(最大流是否只有唯一解)

题目链接:HDU4975

题目意思:

给出一个 n ∗ m n*m nm的表格,现在你需要往每个空格里面填数,你只能填(0-9)范围内的数,现在再告诉你每一行的和以及每一列的和,现在询问你是否存在某种填数方案,如果存在是否唯一。

题目思路:

这是一个非常经典的最大流模型,我们可以类似二分图那样,将行作为二分图的左部,列作为二分图的右部,然后创建源点和汇点,然后看看流入左部的流量之和,是不是等于右部流出的流量之和,如果相等,那么肯定存在填数方案,问题是怎么判断存在多解。
方法是判断跑完最大流的残余网络上是否存在正权环(点数大于2)。
下图为该题第三个样例的网络流图
HDU4975(最大流是否只有唯一解)_第1张图片

下图为上图的残余网络,红色箭头标明的为正权环
HDU4975(最大流是否只有唯一解)_第2张图片

我们可以这么理解这个结论,首先如果存在正权环,那么必然是由原图中的反向边(网络流概念),和正向边共同组成。那么说明环上的反向边的流量,可以通过正向边流向汇点。从而改变图中的残余网络流,那么最大流的方案也就不唯一了。
那么怎么判断环路?还要大于2,因为互为正反边的两条边形成的环,不合法的。所以形成的环点数必然大于2,我们可以通过tarjan把所有强联通分量跑出来,看一下是否有某个强联通分量点数大于2,若存在则存在正权环,否则不存在。

代码:

#include
using namespace std;
typedef long long LL;
#define endl '\n'
const LL inf = 0x3f3f3f3f;
class dinic {
  private:
	  struct node {
		  int v, rev;
		  LL cap;
	  };
	  vector<vector<node>> G;
	  vector<int> dis, cur, vis, hc;
	  int s, d;
	  int bfs() {
		  fill(dis.begin(), dis.end(), 0);
		  dis[s] = 1;
		  queue<int> q;
		  q.push(s);
		  while(!q.empty()) {
			  int u = q.front();
			  q.pop();
			  for(auto& i : G[u]) {
				  if(!dis[i.v] && i.cap > 0) {
					  dis[i.v] = dis[u] + 1;
					  if(i.v == d) return 1;
					  q.push(i.v);
				  }
			  }
		  }
		  return 0;
	  }
	  LL dfs(int u, LL low) {
		  if(u == d) return low;
		  LL flow = 0;
		  for(int &i = cur[u]; i < (int)G[u].size(); i++) {
			  auto &j = G[u][i];
			  if(dis[j.v] == dis[u] + 1 && j.cap > 0) {
				  LL k = dfs(j.v, min(low, j.cap));
				  j.cap -= k;
				  G[j.v][j.rev].cap += k;
				  flow += k;
				  low -= k;
				  if(low == 0) break;
			  }
		  }
		  return flow;
	  }
  public:
	 dinic(int n) {
		 G.resize(n);
		 dis.resize(n);
		 cur.resize(n);
	 }
	 void add(int u, int v, LL w) {
		 G[u].push_back({v, (int)G[v].size(), w});
		 G[v].push_back({u, (int)G[u].size()-1, 0});
	 }
	 LL maxflow(int s, int d) {
		 LL ans = 0;
		 this->s = s;
		 this->d = d;
		 while(bfs()) {
			 fill(cur.begin(), cur.end(), 0);
			 ans += dfs(s,inf);
		 }
		 return ans;
	 }
     bool check(int n) {
        vector<int> dfn(n), low(n), bl(n, -1);
        int tot = 1;
        int num = 0;
        stack<int, vector<int>> s;
        function<void(int)> dfs = [&](int u) {
            dfn[u] = low[u] = tot++;
            s.push(u);
            for (auto i : G[u]) {
                if(i.cap == 0) continue;
                if (!dfn[i.v]) {
                    dfs(i.v);
                    low[u] = min(low[u], low[i.v]);
                }
                else if (bl[i.v] == -1)
                    low[u] = min(dfn[i.v], low[u]);
            }
            if (low[u] == dfn[u]) {
                int tmp;
                do {
                    tmp = s.top();
                    bl[tmp] = num;
                    s.pop();
                } while (tmp != u);
                num++;
            }
        };
        for (int i = 0; i < n; i++) {
            if (bl[i] == -1) {
                tot = 1;
                dfs(i);
            }
        }
        vector<int>vis(n, 0);
        for(int i = 0; i < n; i++){
            if(bl[i] == -1) continue;
            vis[bl[i]]++;
            if(vis[bl[i]] > 2) return true;
        }
        return false;
     }
};

int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    int t; cin >> t;
    for(int ca = 1; ca <= t; ca++) {
        int n, m; cin >> n >> m;
        dinic a(n + m + 2);
        int s = 0, d = n + m + 1;
        LL sum1 = 0, sum2 = 0;
        for(int i = 1; i <= n; i++) {
            int tmp; cin >> tmp;
            sum1 += tmp;
            a.add(s, i, tmp);
            for(int j = 1; j <= m; j++) a.add(i, j + n, 9);
        }
        for(int i = 1; i <= m; i++) {
            int tmp; cin >> tmp;
            sum2 += tmp;
            a.add(i + n, d, tmp);
        }
        cout << "Case #" << ca << ": ";
        if(sum1 == sum2) {
            LL ans = a.maxflow(s, d);
            if(ans == sum1) {
                if(a.check(n + m + 2)) cout << "So young!" << endl;
                else cout << "So simple!" << endl;
            }
            else cout << "So naive!" << endl;
        }
        else cout << "So naive!" << endl;
    }
}

你可能感兴趣的:(HDUOJ)