• UVa 11082 & 最大流的行列模型


    题意:

      给出一个矩阵前i行的和与前j列的和,(i∈[1,r],j属于[1,c]),每个元素ai,j∈[1,20],请你还原出这个矩阵,保证有解.

    SOL:

      给网络流建模跪了,神一样的建图,如果我我会怎么做呢?...搜索?然而每个元素具有行,列双重相关性...暴力都打不出来吧...

      然而我们顺着搜索的方向想,如果每个点的搜索值最终小于这行的和,那么我们应该做什么?增大它!是不是感觉有点增广的想法出来了------>然而我只是瞎BB...事后觉得可以这么想但考场上并不能这么想出来...

      考虑它的建图,因为每个元素至少为1,即流量至少为1,那它就变成一个有上下界的网络流问题...不会怎么办?因为每个元素都大于等于1那么我们把他都减一!

      我们对每一行的和对应一个点与超级源S相连,容量为这一行的和,对于每条列我们建一个点与汇点相连,容量为列的和,然后行与列的点两两相连,容量为19,也就是数的最大值,然后跑一遍最大流,行与列之间每条边的流量就是原矩阵中的元素.

      如何证明它的正确性?

      显然所有行与列的和是相等的,即源汇的出入边一定都满流,同时,我们可以把每一行与所有列的连边上的流量看做该行对此列所做的"贡献",因为最大流一定使源汇出入边满流,所以一定有一种方案.那么这个显然是正确的.

      发现行与列的关系以及和的限制条件,也许是思路突破的关键吧.

      

      警报!警报!警报!!

        自己打的代码莫名TLE了...因为点不多所以老人家写的EK,然而我写的dinic居然TLE了?smg?...因为时间不多先贴上代码,以后有空回来看...模型是关健啊.

     TLE代码:

      

    /*==========================================================================
    # Last modified: 2016-03-08 08:03
    # Filename: uva11082.cpp
    # Description: 
    ==========================================================================*/
    #define me AcrossTheSky 
    #include <cstdio> 
    #include <cmath> 
    #include <ctime> 
    #include <string> 
    #include <cstring> 
    #include <cstdlib> 
    #include <iostream> 
    #include <algorithm> 
      
    #include <set> 
    #include <map> 
    #include <stack> 
    #include <queue> 
    #include <vector> 
     
    #define lowbit(x) (x)&(-x) 
    #define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++) 
    #define FORP(i,a,b) for(int i=(a);i<=(b);i++) 
    #define FORM(i,a,b) for(int i=(a);i>=(b);i--) 
    #define ls(a,b) (((a)+(b)) << 1) 
    #define rs(a,b) (((a)+(b)) >> 1) 
    #define getlc(a) ch[(a)][0] 
    #define getrc(a) ch[(a)][1] 
     
    #define maxn 1000 
    #define maxm 1000000 
    #define pi 3.1415926535898 
    #define _e 2.718281828459 
    #define INF 1070000000 
    using namespace std; 
    typedef long long ll; 
    typedef unsigned long long ull; 
     
    template<class T> inline 
    void read(T& num) { 
        bool start=false,neg=false; 
        char c; 
        num=0; 
        while((c=getchar())!=EOF) { 
            if(c=='-') start=neg=true; 
            else if(c>='0' && c<='9') { 
                start=true; 
                num=num*10+c-'0'; 
            } else if(start) break; 
        } 
        if(neg) num=-num; 
    } 
    /*==================split line==================*/ 
    struct Edge{
    	int from,to,cap,v;
    }e[maxm];
    int r,c;
    int id[maxn][maxn],a[maxn],b[maxn];
    int first[maxn],next[maxm],cur[maxn],d[maxn];
    bool vis[maxn];
    int sume=1,n,S,T;
    void addedge(int x,int y,int cap){
    	sume++; e[sume].from=x; e[sume].to=y; e[sume].cap=cap;
    	next[sume]=first[x]; first[x]=sume; id[x][y]=sume;
    	sume++; e[sume].from=y; e[sume].to=x; e[sume].cap=0;
    	next[sume]=first[y]; first[y]=sume; id[y][x]=sume;
    }
    void reset(){
    	sume=1;
    	a[0]=b[0]=0;
    	memset(e,0,sizeof(e));
    	memset(next,0,sizeof(next));
    	memset(first,0,sizeof(first));
    	memset(a,0,sizeof(a));
    	memset(b,0,sizeof(b));
    	//T=maxn-10,S=0;
    }
    bool bfs(){
    	queue<int>q;
    	FORP(i,S,T) d[i]=INF;
    	//memset(vis,false,sizeof(vis));
    	q.push(S); d[S]=0; //vis[S]=true;
    	while (!q.empty()){
    		int now=q.front(); q.pop();
    		for (int i=first[now];i;i=next[i])
    			if (d[e[i].to]==INF && e[i].cap){
    				d[e[i].to]=d[now]+1;
    				//vis[e[i].to]=true;
    				q.push(e[i].to);
    			}
    	}
    	return d[T]<INF;
    }
    int dfs(int now,int a){
    	if (now==T || !a) return a;
    	int f,flow=0;
    	for (int &i=cur[now];i;i=next[i])
    		if (d[now]+1==d[e[i].to] && (f=dfs(e[i].to,min(a,e[i].cap)))>0){
    			flow+=f; a-=f; e[i].cap-=f; e[i].v+=f; e[i^1].cap+=f;
    			if (!a) break;
    		}
    	return flow;
    }
    void dinic(){
    	int flow=0;
    	while (bfs()){
    		FORP(i,0,n) cur[i]=first[i];
    		flow+=dfs(S,INF);
    	}
    }
    int main(){
    	int cas; read(cas); //int cass=1;
    	FORP(cass,1,cas){
    		reset();
    		scanf("%d%d",&r,&c);
    		n=r+c+1; S=0; T=r+c+4;
    		FORP(i,1,r) scanf("%d",&a[i]);//read(a[i]);
    		FORP(i,1,c) scanf("%d",&b[i]);//read(b[i]);
    		FORP(i,1,r) addedge(0,i,a[i]-a[i-1]-c);
    		FORP(i,1,r)
    			FORP(j,r+1,r+c+1) addedge(i,j,19);
    		FORP(j,r+1,r+c+1) addedge(j,T,b[j-r]-b[j-r-1]-r);
    		printf("Matrix %d
    ",cass); //cass++;
    		dinic();
    		FORP(i,1,r)
    			FORP(j,1,c) 
    			printf("%d%c",e[id[i][j+r]].v+1,(j==c)?'
    ':' ');
    		if (cas) cout << endl;
    	}
    }
    

     lrj代码:

      

    // UVa11082 Matrix Decompressing
    // Rujia Liu
    // Slower version with EdmondsKarp
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<vector>
    #include<algorithm>
    using namespace std;
    
    const int maxn = 50 + 5;
    const int INF = 1000000000;
    
    struct Edge {
      int from, to, cap, flow;
      Edge(int u, int v, int c, int f):from(u),to(v),cap(c),flow(f) {}
    };
    
    struct EdmondsKarp {
      int n, m;
      vector<Edge> edges;    // 边数的两倍
      vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
      int a[maxn];           // 当起点到i的可改进量
      int p[maxn];           // 最短路树上p的入弧编号
    
      void init(int n) {
        for(int i = 0; i < n; i++) G[i].clear();
        edges.clear();
      }
    
      void AddEdge(int from, int to, int cap) {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
      }
    
      int Maxflow(int s, int t) {
        int flow = 0;
        for(;;) {
          memset(a, 0, sizeof(a));
          queue<int> Q;
          Q.push(s);
          a[s] = INF;
          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(!a[e.to] && e.cap > e.flow) {
                p[e.to] = G[x][i];
                a[e.to] = min(a[x], e.cap-e.flow);
                Q.push(e.to);
              }
            }
            if(a[t]) break;
          }
          if(!a[t]) break;
          for(int u = t; u != s; u = edges[p[u]].from) {
            edges[p[u]].flow += a[t];
            edges[p[u]^1].flow -= a[t];
          }
          flow += a[t];
        }
        return flow;
      }
    };
    
    EdmondsKarp g;
    int no[maxn][maxn];
    
    int main() {
      int T, R, C, v, kase = 0;
      scanf("%d", &T);
      for(int kase = 1; kase <= T; kase++) {
        scanf("%d%d", &R, &C);
        g.init(R+C+2);
        int last = 0;
        for(int i = 1; i <= R; i++) {
          scanf("%d", &v);
          g.AddEdge(0, i, v - last - C); // row sum is v - last
          last = v;
        }
        last = 0;
        for(int i = 1; i <= C; i++) {
          scanf("%d", &v);
          g.AddEdge(R+i, R+C+1, v - last - R); // col sum is v - last
          last = v;
        }
        for(int i = 1; i <= R; i++)
          for(int j = 1; j <= C; j++) {
            g.AddEdge(i, R+j, 19);
            no[i][j] = g.edges.size() - 2; // no[i][j] is the index of arc for cell(i,j)
          }
        g.Maxflow(0, R+C+1);
    
        printf("Matrix %d
    ", kase);
        for(int i = 1; i <= R; i++) {
          for(int j = 1; j <= C; j++)
            printf("%d ", g.edges[no[i][j]].flow + 1); // we subtracted 1 from every cell
          printf("
    ");
        }
        printf("
    ");
      }
      return 0;
    }
    
    Sometimes it s the very people who no one imagines anything of. who do the things that no one can imagine.
  • 相关阅读:
    bzoj2190[SDOI2008]仪仗队(欧拉函数)
    洛谷P3601签到题(欧拉函数)
    bzoj2818 Gcd(欧拉函数)
    poj2104 K-th Number(主席树静态区间第k大)
    只要有它,你就永远不会被打垮!
    网站美化常见CSS
    虚拟机安装CentOS6.4
    提高工作效率是有秘诀的
    不要消费信任
    项目经理必备7要素
  • 原文地址:https://www.cnblogs.com/YCuangWhen/p/5255494.html
Copyright © 2020-2023  润新知