第一道自己yy的网络流 其实是很水的题目
被猪坑了好长时间
建立二分图 分别是猪圈和买猪的人..
然后用边集数组记录能划到一个范围的猪圈
每次来取猪的时候 先讲一个范围的猪圈与买主连一条边
然后更新边集数组 就ac了 网络卡了 我就连交了3次
时间有16ms 也有0ms的 诧异..
代码:
#include <cstdio>
#include <cstring>#include <iostream>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 2000;
const int inf = 0x7fffffff;
const int s = 0;
int p[MAXN];
int e[MAXN][MAXN];
int find ( int x )
{
while ( p[x] != x )
x = p[x] ;
return x;
}
struct edge{
int v,next,w;
}edge[1000000];
int head[2*MAXN],cnt;//for sap
void debug ( )
{
cout << "here" << endl;
}
void addedge(int u, int v, int w)
{
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
edge[cnt].v = u;
edge[cnt].w = 0;
edge[cnt].next = head[v];
head[v] = cnt++;
}
int sap(int t)
{
//debug ();
int pre[2*MAXN],cur[2*MAXN],dis[2*MAXN],gap[2*MAXN]; //gap标记断层 这里可能会挂掉
int flow = 0 , aug = inf ,u;
bool flag;
for (int i = 0 ; i <= t ; ++i)
{
cur[i] = head[i];
gap[i] = dis[i]=0;
}
//debug ();
gap[s] = t+1;
u = pre[s] = s;
while (dis[s] <= t)
{
//debug () ;
flag = 0 ;
for (int &j = cur[u] ; ~j ; j = edge[j].next)
{
int v = edge[j].v;
//debug ();
//cout << u << " **** " << v << endl;
if (edge[j].w > 0 && dis[u] == dis[v]+1)
{
flag = 1;
if( edge[j].w < aug )aug = edge[j].w;
pre[v] = u;
u = v;
if (u == t)
{
flow += aug;
while ( u != s )
{
u = pre[u];
edge[cur[u]].w -= aug;
edge[cur[u]^1].w += aug;
}
aug = inf;
}
break;
}
}
if ( flag )continue ;
int mindis = t+1;
for (int j = head[u]; ~j ; j = edge[j].next)
{
int v = edge[j].v;
if ( edge[j].w > 0 && dis[v] < mindis)
{
mindis = dis[v];
cur[u] = j;
}
}
if( --gap[dis[u]] == 0)break;
gap[ dis[u] = mindis+1 ]++;
u = pre[u];
}
return flow;
}
void init ()
{
memset (head , -1 , sizeof(head));
cnt=0;
for ( int i = 0 ; i < MAXN ; i ++ )
e[i][0] = 0;
}
void insert ( int a, int b )
{
int flag = 0;
for ( int i = 1 ; i <= e[a][0] ; i ++ )
{
if ( e[a][i] == b )
flag = 1;
}
if ( flag == 0 )
{
e[a][0] ++;
e[a][e[a][0]] = b;
}
}
int main()
{
int m , n;
while ( scanf("%d%d" , &m , &n )!= EOF )
{
init();
int num[MAXN];
int pig[MAXN];
//memset ( p_time , -1 , sizeof ( p_time ));
//memset ( used , 0 , sizeof ( used ));
for ( int i = 1 ; i <= m ; i ++ )
scanf("%d" , &num[i] );
for ( int i = 1 ; i <= m ; i ++ )
addedge ( 0 , i , num[i] );
// for ( int i = 0 ; i <= m+n ; i ++ )
// for ( int j = head[i] ; j != -1 ; j = edge[j].next )
// cout << i << "***** " << edge[j].v << endl,getchar();
for ( int i = 0 ; i < n ; i ++ )
{
int a , b;
scanf("%d" , &a );
for ( int j = 0 ; j < a ; j ++ )
{
scanf("%d", &pig[j] );
for ( int k = 1 ; k <= e[pig[j]][0] ; k ++ )
addedge ( e[pig[j]][k] , m+1+i , inf );
addedge ( pig[j] , m+1+i, inf );
}
for ( int j = 0 ; j < a ; j ++ )
for ( int k = 0 ; k < a ; k ++ )
insert ( pig[j] , pig[k] );
scanf("%d" , &b );
addedge ( m+1+i , m+1+n , b );
}
printf("%d\n" , sap ( n+m+1 ));
}
return 0;
}
网上其他的方法:
开始时用猪圈数当节点,发现节点数很多,而且顾客的先后顺序不容易控制,然后发现,顾客的数目只有100个,那么以顾客为节点就容易多了,如果某个顾客是第一次拿某个猪圈的钥匙,则在源与顾客间连线,大小为猪的初始数目,否则就把前一个拥有钥匙的人和这个人连一条线,大小为无穷大,每个顾客都与汇相连,然后求最大流即可
其实这个方法就是把上面的节点压缩了 这样就能快很多..