和HDOJ4888是一样的问题,最大流判断多解
1.把ISAP卡的根本出不来结果,只能把全为0或者全为满流的给特判掉......
2.在残量网络中找大于2的圈要用一种类似tarjian的方法从汇点开始找,判断哪些点没有到汇点
3 1 1 5 5 2 2 0 10 0 10 2 2 2 2 2 2
Case #1: So simple! Case #2: So naive! Case #3: So young!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn=20000;
const int maxm=500000;
const int INF=0x3f3f3f3f;
struct Edge
{
	int to,next,cap,flow;
}edge[maxm];
int Size,Adj[maxn];
int gap[maxn],dep[maxn],pre[maxn],cur[maxn];
void init()
{
	Size=0; memset(Adj,-1,sizeof(Adj));
}
void addedge(int u,int v,int w,int rw=0) 
{
    edge[Size].to=v; edge[Size].cap=w; edge[Size].next=Adj[u];
    edge[Size].flow=0; Adj[u]=Size++;
    edge[Size].to=u; edge[Size].cap=rw; edge[Size].next=Adj[v];
    edge[Size].flow=0; Adj[v]=Size++;
}
int sap(int start,int end,int N)
{
    memset(gap,0,sizeof(gap));
    memset(dep,0,sizeof(dep));
    memcpy(cur,Adj,sizeof(Adj));
    int u=start;
    pre[u]=-1; gap[0]=N;
    int ans=0;
    while(dep[start]<N)
    {
        if(u==end)
        {
            int Min=INF;
            for(int i=pre[u];~i;i=pre[edge[i^1].to])
                if(Min>edge[i].cap-edge[i].flow)
                    Min=edge[i].cap-edge[i].flow;
            for(int i=pre[u];~i;i=pre[edge[i^1].to])
            {
                edge[i].flow+=Min;
                edge[i^1].flow-=Min;
            }
            u=start;
            ans+=Min;
            continue;
        }
        bool flag=false;
        int v;
        for(int i=cur[u];~i;i=edge[i].next)
        {
            v=edge[i].to;
            if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u])
            {
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if(flag)
        {
            u=v;
            continue;
        }
        int Min=N;
        for(int i=Adj[u];~i;i=edge[i].next)
            if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min)
            {
                Min=dep[edge[i].to];
                cur[u]=i;
            }
        gap[dep[u]]--;
        if(!gap[dep[u]]) return ans;
        dep[u]=Min+1;
        gap[dep[u]]++;
        if(u!=start) u=edge[pre[u]^1].to;
    }
    return ans;
}
int n,m;
int a[maxn],b[maxn];
bool vis[maxn],no[maxn];
int Stack[maxm],stk;
bool dfs(int u,int pre,bool flag)
{
	vis[u]=true;
	Stack[stk++]=u;
	for(int i=Adj[u];~i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(v==pre) continue;
		if(edge[i].flow>=edge[i].cap) continue;
		if(!vis[v])
		{
			if(dfs(v,u,edge[i^1].cap>edge[i^1].flow)) return true;
		}
		else if(!no[v]) return true;
	}
	if(flag==false)
	{
		while(true)
		{
			int v=Stack[--stk];
			no[v]=true;
			if(v==u) break;
		}
	}
	return false;
}
int main()
{
	int T_T,cas=1;
	scanf("%d",&T_T);
	while(T_T--)
	{
		scanf("%d%d",&n,&m);
		int sum1=0,sum2=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",a+i); sum1+=a[i];
		}
		for(int i=1;i<=m;i++)
		{
			scanf("%d",b+i); sum2+=b[i];
		}
		if(sum1!=sum2)
		{
			printf("Case #%d: So naive!\n",cas++);
			continue;
		}
		if(sum1==sum2&&((sum1==0)||(sum1==n*m*9)))
		{
			printf("Case #%d: So simple!\n",cas++);
			continue;
		}
		/*************build graph*****************/
		init();
		for(int i=1;i<=n;i++) addedge(0,i,a[i]);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				addedge(i,n+j,9);
		for(int i=1;i<=m;i++) addedge(i+n,n+m+1,b[i]);
		/*************build graph*****************/
		int MaxFlow=sap(0,n+m+1,n+m+2);
		if(MaxFlow!=sum1)
		{
			printf("Case #%d: So naive!\n",cas++);
			continue;
		}
		stk=0;
		memset(vis,0,sizeof(vis));
		memset(no,0,sizeof(no));
		if(dfs(n+m+1,n+m+1,0))
		{
			printf("Case #%d: So young!\n",cas++);
		}	
		else
		{
			printf("Case #%d: So simple!\n",cas++);
		}
	}
	return 0;
}
HDOJ 4975 A simple Gaussian elimination problem.
原文:http://blog.csdn.net/ck_boss/article/details/39960111