图入度大于出度 java实现_POJ 1637 混合图求欧拉回路 最大流实现

前面讲过了无向图,有向图求欧拉回路,欧拉通路的做法。可以直接根据度数来判断,当然前提是这是一个连通图。

这道题既有无向边,又有有向边,然后求欧拉回路。

采用的方法是最大流。

具体处理方法。

首先,我们对无向边,进行随意定边。定完边之后,求出每个点的出度入度。如果某个点的出度入度之差为奇数,那么就无法形成欧拉回路。

接下来所有的点的度数之差都是偶数了,对于有向边,我们不需要处理。

对于无向边,我们给初始随意定的边的方向,流量+1,即如果一条无向边,a - b,我们初始给他定边是a -> b,那么我们将a -> b的流量+1。

然后对于每个入度出度之差为偶数的点,如果出度大于入度。那么我们连一条S到该点的边,流量为 (出度 - 入度)/ 2 。

同理,对于入度大于出度的边,我们连一条该点到T的边,流量为(入度- 出度)/ 2 。

接下来我们跑一遍最大流即可以了。

如果该图是满流的话,那么证明存在欧拉回路。否则不存在。

具体证明请看这里。http://zhyu.me/acm/zoj-1992-and-poj-1637.html

CODE:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PI acos(-1.0)

#define Max 2505

#define inf 1<<28

#define LL(x) ( x << 1 )

#define RR(x) ( x << 1 | 1 )

#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )

#define ll long long

#define mem(a,b) memset(a,b,sizeof(a))

#define mp(a,b) make_pair(a,b)

#define PII pair

using namespace std;

inline void RD(int &ret) {

char c;

do {

c = getchar();

} while(c < '0' || c > '9') ;

ret = c - '0';

while((c=getchar()) >= '0' && c <= '9')

ret = ret * 10 + ( c - '0' );

}

inline void OT(int a){

if(a >= 10)OT(a / 10) ;

putchar(a % 10 + '0') ;

}

#define N 1005

#define M 100005

struct ed{

int s , e , flag ;

}road[M] ;

int in[N] ,out[N] ;

struct kdq{

int e , next ,c ;

}ed[M] ;

int head[N] ,num ;

void add(int s ,int e ,int c){

ed[num].e = e ;

ed[num].c = c ;

ed[num].next = head[s] ;

head[s] = num ++ ;

ed[num].e = s ;

ed[num].c = 0 ;

ed[num].next = head[e] ;

head[e] = num ++ ;

}

void init(){

mem(head , -1) ;

mem(in , 0) ;

mem(out , 0) ;

}

int S , T ;

int dis[N] ,qe[M] ,deep[N] ;

int n , m ;

/***dinic模版***/

int dinic_bfs(){

mem(deep, -1) ;

deep[S] = 0 ;

int h = 0 , t = 0 ;

qe[h ++ ] = S ;

while(h > t){

int tt = qe[t ++ ] ;

for (int i = head[tt] ; ~i ; i = ed[i].next ){

int e = ed[i].e ;

int c = ed[i].c ;

if(c > 0 && deep[e] == -1){

deep[e] = deep[tt] + 1 ;

qe[h ++ ] = e ;

}

}

}

return deep[T] != -1 ;

}

int dinic_dfs(int now ,int f){

if(now == T)return f ;

int flow = 0 ;

for (int i = head[now] ; ~i ; i = ed[i].next ){

int e = ed[i].e ;

int c = ed[i].c ;

if((f - flow) > 0 && c > 0 && deep[e] == deep[now] + 1 ){

int mm = min(f - flow ,c) ;

int nn = dinic_dfs(e , mm) ;

flow += nn ;

ed[i].c -= nn ;

ed[i ^ 1].c += nn ;

}

}

if(flow == 0)deep[now] = -2 ;

return flow ;

}

int dinic(){

int MaxFlow = 0 ;

while(dinic_bfs()){

MaxFlow += dinic_dfs(S ,inf) ;

}

return MaxFlow ;

}

/******/

int main() {

int t ;

cin >> t ;

while(t -- ){

cin >> n >> m ;

init() ;

S = 0 , T = n + 1 ;

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

RD(road[i].s) ;RD(road[i].e) ;RD(road[i].flag) ;

out[road[i].s] ++ ;

in[road[i].e] ++ ;

}

bool flag = 0 ;

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

if(abs(in[i] - out[i]) & 1){//存在度数之差为奇数的点

puts("impossible") ;

flag = 1 ;

break ;

}

}

if(flag)continue ;

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

if(road[i].flag)continue ;

add(road[i].s ,road[i].e , 1) ;//初始定边我都是按a -> b的方向

}

int MF = 0 ;

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

if(out[i] > in[i]){

add(S , i , (out[i] - in[i]) / 2 ) ;

MF += (out[i] - in[i]) / 2 ;

}

else if(in[i] > out[i]){

add(i , T , (in[i] - out[i]) / 2) ;

}

}

int MaxFlow = dinic() ;

if(MaxFlow == MF){

puts("possible") ;

}

else puts("impossible") ;

}

return 0 ;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值