hdu4975 A simple Gaussian elimination problem.正确解法 最大流+删边判环

来源:互联网 发布:windows 多进程编程 编辑:程序博客网 时间:2024/06/16 12:18

题意:有n行m列矩阵,给出各行的和、各列的和,矩阵元素需要为0~9,判断无解、唯一解、多解。

题解:网络流+判环。

和hdu4888几乎一模一样,hdu4888题解链接:http://www.cnblogs.com/yuiffy/p/3891639.html

这题的做法就是hdu4888的做法,点上面的链接怒看如何建图,我下面说这题的不同之处。

可以想到,如果选择一条边递归,然后从递归里出来了,说明没找到环,那么走这条边肯定找不到环,以后也不用走了,可以把这条边删了。或者这条边流量为0,也可以删了。

这样的话每条边最多只进一次,O(m)。

其实4888也可以用这种方法,不过4888还要输出结果,所以先记录结果再删。


//#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<cmath>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<map>#include<set>#include<stack>#include<queue>using namespace std;#define ll long long#define usll unsigned ll#define mz(array) memset(array, 0, sizeof(array))#define minf(array) memset(array, 0x3f, sizeof(array))#define REP(i,n) for(i=0;i<(n);i++)#define FOR(i,x,n) for(i=(x);i<=(n);i++)#define RD(x) scanf("%d",&x)#define RD2(x,y) scanf("%d%d",&x,&y)#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)#define WN(x) prllf("%d\n",x);#define RE  freopen("D.in","r",stdin)#define WE  freopen("1biao.out","w",stdout)#define mp make_pair#define pb push_backint ans;int r[511],co[511];int k,nr,nc;int sumr,sumc;const int maxn=1111;//点数const int maxm=555555;//边数const int inf=9;//MAXINTstruct vnode {    int v,next;    int cap;};int cnt,head[maxn];int h[maxn],g[maxn],d[maxn];//g[i]为标号为i的结点个数,h[i]为i结点的标号,d[]当前弧优化,记录当前弧bool found;int n,m,st,ed;//n个点m条边int augc,flow;//augc为增广路容量,flow为最大流vnode e[maxm];inline void add(const int &x,const int &y,const int &z) {    e[cnt].v=y;    e[cnt].cap=z;    e[cnt].next=head[x];    head[x]=cnt;    cnt++;    e[cnt].v=x;    e[cnt].cap=0;    e[cnt].next=head[y];    head[y]=cnt;    cnt++;}bool walked[maxn];bool dfs(const int &x,const int &prex) {///深搜判环    int biu=-1;    walked[x]=true;    for (int i=head[x]; i!=-1; i=e[i].next) {        if(e[i].v==prex){            biu=i;            continue;        }        if (e[i].cap>0) {            if(walked[e[i].v]) return true;            if(dfs(e[i].v,x)) return true;        }        if(biu==-1) head[x]=e[i].next;///删边,因为这条边为0或者走了这条边却没发现环        else e[biu].next=e[i].next;        //biu=i;    }    walked[x]=false;    return false;}void aug(const int &m) {    int mini,minh=n-1;    int augco=augc;    int &i=d[m];///当前弧优化    if (m==ed) { //如果当前结点为汇点        found=true;        flow+=augc;    //增加流量        return;    }    for (; i!=-1; i=e[i].next) { //寻找容许边        //printf("m=%d,i=%d,e[i].v=%d,e[i].cap=%d,e[i].next=%d\n",m,i,e[i].v,e[i].cap,e[i].next);        //getchar();        if (e[i].cap && h[e[i].v]+1==h[m]) { //如果残留容量大于0,如果是容许边            if (e[i].cap < augc)  augc=e[i].cap;//如果容许边流量小于当前增广路流量 则更新增广路流量            //d[m]=i;    //把i定为当前弧            aug(e[i].v);    //递归            if (h[st]>=n) return; //GAP 如果源点距离标号大于n 则停止算法            if (found) break;    //如果找到汇点 则退出寻找            augc=augco;//没找到就还原当前的流        }    }    if (!found) {      //重标号        for (int i=head[m]; i!=-1; i=e[i].next) //找那个标号,这里不能用d[m]开始,不然会蛋疼            if (e[i].cap && h[e[i].v]<minh) {                minh=h[e[i].v];                mini=i;            }        g[h[m]]--;                                 //GAP 距离为        if (!g[h[m]]) h[st]=n;                 //GAP        h[m]=minh+1;        d[m]=mini;        g[h[m]]++;                                 //GAP    } else {        //修改残量        e[i].cap-=augc;        e[i^1].cap+=augc;    }}inline void farm() {    int i,j,x,y,z;    memset(head,-1,sizeof(head));    cnt=0;    n=nc+nr+2;    st=n-1;    ed=n;    for(i=1; i<=nc; i++)        add(st,i,co[i]);    for(i=1; i<=nr; i++)        add(nc+i,ed,r[i]);    for(i=1; i<=nc; i++)        for(j=1; j<=nr; j++)            add(i,j+nc,k);    memset(h,0,sizeof(h));    memset(g,0,sizeof(g));    g[0]=n;    flow=0;    for(i=1; i<=n; i++)        d[i]=head[i];//当前弧初始化    while(h[st]<n) {        augc=inf;//初始化增广路容量为正无穷大        found=false;        aug(st);//从源点开始找    }    if(flow!=sumr) {        ans=0;        return;    }    memset(walked,false,sizeof(walked));    for(i=1; i<=nr; i++) { ///因为建图的特性,有环的话环肯定包含1~nr中的点,也就是表示行的结点        if(dfs(i,-1)) {            ans=2;            return;        }    }    ans=1;    //printf("%d\n",flow);}inline void read(int &a) {///读入优化    char ch;    bool flag = false;    a = 0;    while(!((((ch = getchar()) >= '0') && (ch <= '9')) || (ch == '-')));    if(ch != '-') {        a *= 10;        a += ch - '0';    } else {        flag = true;    }    while(((ch = getchar()) >= '0') && (ch <= '9')) {        a *= 10;        a += ch - '0';    }    if(flag) {        a = -a;    }}int main() {    //RE;    //WE;    int i,j,cas=1,t;    scanf("%d",&t);    while(t--) {        scanf("%d%d",&nr,&nc);        k=9;        sumr=0;        sumc=0;        for(i=1; i<=nr; i++) {            //scanf("%d",&r[i]);            read(r[i]);            sumr+=r[i];        }        for(i=1; i<=nc; i++) {            //scanf("%d",&co[i]);            read(co[i]);            sumc+=co[i];        }        ans=0;        if(sumr==sumc)farm();        if(ans==0) printf("Case #%d: So naive!\n",cas++);        else if(ans!=1) {            printf("Case #%d: So young!\n",cas++);        } else {            printf("Case #%d: So simple!\n",cas++);        }    }    //cout<<"end";    return 0;}



阅读全文
0 0
原创粉丝点击