您的位置:首页 > 其它

bzoj4464

2016-05-20 15:50 323 查看
OJ上放的题解是网络流这里先放一份(然而是过不了的,血泪教训,40w个点,上百万条边,跑毛啊.)这里还是放一份代码.

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
#define inf 1000000000
using namespace std;
struct node {int to;int next;int len;};
node bian[3000010],edge[500010];
int size = 1,first[400010],tot = 0,fir[400010],p[400010],cnt = 0;
int N,s,t,dis[400010],stack[3000010],n,a,b;
long long cost;
bool visit[400010],exist[400010];
void inser(int x,int y,int z) {
size ++;
bian[size].to = y;
bian[size].next = first[x];
first[x] = size;
bian[size].len = z;
}
void add(int x,int y) {
tot ++;
edge[tot].to = y;
edge[tot].next = fir[x];
fir[x] = tot;
}
void dfs(int x,int Anc) {
visit[x] = true;
if(p[x] == 0) p[x] =  ++ cnt;
for(int u = fir[x];u;u = edge[u].next)
{
if(edge[u].to == Anc) continue;
cnt = cnt + 1;
inser(p[x],cnt + N,inf);
inser(cnt + N,p[x],0);
inser(p[x] + N,cnt + N,inf);
inser(cnt + N,p[x] + N,0);
if(visit[edge[u].to] == true)
{
inser(cnt,p[edge[u].to] + N,inf);
inser(p[edge[u].to] + N,cnt,0);
inser(cnt + N,p[edge[u].to] + N,inf);
inser(p[edge[u].to] + N,cnt + N,0);
}
else
{
p[edge[u].to] = ++ cnt;
inser(cnt - 1,p[edge[u].to] + N,inf);
inser(p[edge[u].to] + N,cnt - 1,0);
inser(cnt + N - 1,p[edge[u].to] + N,inf);
inser(p[edge[u].to] + N,cnt + N - 1,0);
dfs(edge[u].to,x);
}
}
}
int Dfs(int x,int F) {
if(x == t) return F;
int ret = 0;
for(int u = first[x];u && F;u = bian[u].next)
if(dis[bian[u].to] == dis[x] + 1 && bian[u].len > 0)
{
int d = Dfs(bian[u].to,min(F,bian[u].len));
F -= d;
ret += d;
bian[u].len -= d;
bian[u ^ 1].len += d;
}
if(ret == 0 || F == 0) dis[x] = -5;
return ret;
}
bool spfa(int x,int y) {
int head = 0,tail = 1;
for(int i = 0;i <= t;i ++) dis[i] = inf;
stack[1] = x;dis[x] = 0;
while(head != tail)
{
head = head + 1;
if(head == 1000000) head = 1;
int k = stack[head];
exist[k] = false;
for(int u = first[k];u;u = bian[u].next)
{
if(dis[bian[u].to] == inf && bian[u].len > 0)
{
dis[bian[u].to] = dis[k] + 1;
tail ++;
if(tail == 1000000) tail = 1;
stack[tail] = bian[u].to;
exist[bian[u].to] = true;
}
}
}
return dis[y] <= 1000000;
}
int maxflow(int x,int y) {
int ret = 0,tim = 0;
while(spfa(x,y))
tim ++,ret += Dfs(s,inf);
return ret;
}
int main() {
scanf("%d",&n);
for(int i = 2;i <= n;i ++)
{
scanf("%d",&a);
a = a + 1;
scanf("%d",&b);
b = b + 1;
add(a,b);
}
N = 2 * n - 1;
memset(visit,false,sizeof(visit));
for(int i = 1;i <= n;i ++)
if(visit[i] == false) dfs(i,0);
s = 0,t = N * 2 + 1;
for(int i = 1;i <= N;i ++)
{
inser(s,i,1);
inser(i,s,0);
}
for(int i = N + 1;i <= 2 * N;i ++)
{
inser(i,t,1);
inser(t,i,0);
}
N = N - maxflow(s,t);
printf("%d",N);
}


写完网络流爆炸之后我发现艹这不是sb贪心吗?我们考虑这样贪心,对于每个点i,从它的儿子记录有多少条到它的链,有多少条到它儿子的链,分别设为A,B,然后我们发现1个A可以抵掉1个B,为什么在这里抵掉是最优的呢?因为就算一条这样的链现在不抵掉,就算之后抵掉了其它的链,那么和当前的贡献一样,抵不掉其它链反而更亏,所以说不抵白不抵,因为可以这样抵,所以说其实每个点只用记录两个信息f[x],g[x]表示有多少条链,链的方向就可以了.注意转移的时候如果儿子节点g[son]不等于当前边的方向的话,那么f[son]直接算到答案中去,同时x的A(B)只对应加1,否则就加f[son].注意当f[son]=0的时候要特判一下.每次把min(A,B)加到答案中再把剩下的链数记录在f[x]中,最后答案加上f[1].复杂度o(n).mdzz网络流.

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
using namespace std;
struct node {int to;int next;int flag;};node bian[200010];
int size = 0,first[200010],f[200010],g[200010],n,a,b,Ans;
void inser(int x,int y,int z) {
size ++;
bian[size].to = y;
bian[size].next = first[x];
bian[size].flag = z;
first[x] = size;
}
void dfs(int x,int Anc) {
int A = 0,B = 0;
for(int u = first[x];u;u = bian[u].next) {
if(bian[u].to == Anc) continue;
dfs(bian[u].to,x);
if(bian[u].flag == 1)
{
if(f[bian[u].to])
{
if(g[bian[u].to])
{
A += f[bian[u].to];
}
else Ans += f[bian[u].to],A ++;
}
else A ++;
}
else
{
if(f[bian[u].to])
{
if(!g[bian[u].to])
{
B += f[bian[u].to];
}
else Ans += f[bian[u].to],B ++;
}
else B ++;
}
}
int delta = min(A,B);
Ans += delta;
A -= delta;
B -= delta;
if(A > 0)
{
f[x] = A;
g[x] = 1;
}
else if(B > 0)
{
f[x] = B;
g[x] = 0;
}
else f[x] = 0,g[x] = 1;
}
int main() {
scanf("%d",&n);
for(int i = 2;i <= n;i ++)
{
scanf("%d%d",&a,&b);
a = a + 1;
b = b + 1;
inser(a,b,1);
inser(b,a,0);
}
dfs(1,1);
cout<<Ans + f[1];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: