CF1383F. Special Edges

Posted gmh77

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1383F. Special Edges相关的知识,希望对你有一定的参考价值。

题目大意

给出一个有向图,有k条特殊边,每条边每次询问指定容量

求每次询问的最大流

n,m<=1e4,k<=10,q<=2e5,边权w<=25

题解

最大流=最小割,所以枚举k条边的割边情况,最大流=最小割=min(枚举的割边+剩余的最小割)

建一个新图求剩余部分的最小割
①非k条边:直接加到新图
②k条中确定割了的边:不加
③k条中确定没割的边:设为inf,因为割这条不如把剩下的都割了,所以不会割

求新图的最小割(最大流)就是剩余的最小割,加上枚举的割边代价就是一组方案


假设k条全部都割了,就是全k条都不加的情况,求出了这种情况的答案和残量网络
然后在这基础上加一条inf边,就可以得到某条边不割的情况,这样只加一条边就可以跑FF算法
(手玩一下发现加边容量为25即可,如果inf边跑了超过25则一定不如确定割掉优,这样一次跑的复杂度就是O(25*m)

具体实现,先跑一遍dinic/sap,然后枚举删边情况,记录上一次的残量网络,每次在上一次的基础上加一条25边跑FF
最后根据询问的wi高维前缀和来算答案

时间O(玄),因为第一次的dinic就理论\\(O(n^2m)\\)了……

code

没过,卡不动

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define Min(a,b) a=min(a,b)
#define Max(a,b) a=max(a,b)
#define low(x) ((x)&-(x))
#define ll long long
#define inf 1000000
#define st 1
#define ed n
//#define file
using namespace std;

struct type
	int x,y,z;
;
bool cmp(type a,type b)

	return a.x<b.x || a.x==b.x && a.y<b.y;


void Read(int &x)

	char ch;
	x=0;
	ch=getchar();
	while (!(ch>=\'0\' && ch<=\'9\')) ch=getchar();
	while ( (ch>=\'0\' && ch<=\'9\')) x=x*10+ch-\'0\',ch=getchar();

char St[21];
void Write(int x)

	if (!x)
	
		printf("0\\n");
		return;
	
	int i=0;
	while (x) St[++i]=x%10+\'0\',x/=10;
	while (i) putchar(St[i]),--i;
	putchar(\'\\n\');


bool data87=0;
int n,m,K,Q,i,j,k,l,x,y,z;
bool bz_end,bz_p[10001];
int wf[10011],wg[10011];
struct Graph
	int a[20011][3],ls[10011],cur[10011],len;
	
	void clear()
	
		memset(ls,0,sizeof(ls)),len=1;
		memcpy(cur,ls,sizeof(ls));
	
	
	void New(int x,int y,int z)
	
		++len;
		a[len][0]=y;
		a[len][1]=ls[x];
		ls[x]=cur[x]=len;
		a[len][2]=z;
	
	
	int dfs_sap(int t,int w)
	
		int i,v,use=0;
		if (t==ed) bz_end=1;return w;
		
		bz_p[t]=1;
		
		for (i=cur[t]; i; i=a[i][1])
		
			cur[t]=i;
			if (a[i][2] && wf[t]==wf[a[i][0]]+1)
			
				v=dfs_sap(a[i][0],min(w,a[i][2]));
				a[i][2]-=v;
				a[i^1][2]+=v;
				w-=v;
				use+=v;
				
				if (!w) bz_p[t]=0;return use;
			
		
		cur[t]=ls[t];
		bz_p[t]=0;
		
		--wg[wf[t]];
		if (wg[wf[t]]==0)
		
			wf[st]=ed+2;
			return use;
		
		++wf[t],++wg[wf[t]];
		
		return use;
	
	
	int dfs(int t,int w)
	
		int i,v,use=0;
		if (t==ed) bz_end=1;return w;
		
		bz_p[t]=1;
		
		for (i=ls[t]; i; i=a[i][1])
		
			cur[t]=i;
			if (a[i][2] && !bz_p[a[i][0]])
			
				v=dfs(a[i][0],min(w,a[i][2]));
				if (!v) continue;
				
				a[i][2]-=v;
				a[i^1][2]+=v;
				w-=v;
				use+=v;
				
				return use;
			
		
		
		return use;
	
	
	void Copy(Graph& G0)
	
		int i,j;
		len=G0.len;
		memcpy(a,G0.a,sizeof(a[0])*(G0.len+1));
		memcpy(ls,G0.ls,4*(n+1));
		memcpy(cur,ls,4*(n+1));
	
 G[11];
int A[10001][3];
int Ans[1024],sum[1024],ans;
bool bz[11];
int w[11];
vector<type> v;

void G0_init()

	G[0].len=1;
	fo(i,K+1,m)
	if (A[i][2]!=-1)
	
		G[0].New(A[i][0],A[i][1],A[i][2]);
		G[0].New(A[i][1],A[i][0],0);
	
	n=n;
	memset(wf,0,sizeof(wf));
	memset(wg,0,sizeof(wg));
	memcpy(G[0].cur,G[0].ls,sizeof(G[0].ls));
	wg[0]=ed;
	while (wf[st]<=ed+1)
	Ans[(1<<K)-1]+=G[0].dfs_sap(st,inf);


void dg(int t,int s,int Gid,int ans)

	int i;
	if (t>K)
	
		Ans[s]=ans;
		return;
	
	
	bz[t]=1;A[t][2]=-1;
	dg(t+1,s+(1<<(t-1)),Gid,ans);
	
	G[Gid+1].Copy(G[Gid]);
	G[Gid+1].New(A[t][0],A[t][1],25);
	G[Gid+1].New(A[t][1],A[t][0],0);
//	if (!data87)
	
		bz[t]=0;A[t][2]=25;
		do
			memset(bz_p,0,sizeof(bz_p));
			bz_end=0;
			ans+=G[Gid+1].dfs(st,inf);
		while (bz_end);
	
	dg(t+1,s,Gid+1,ans);


int main()

	#ifdef file
	freopen("CF1383F.in","r",stdin);
//	freopen("CF1383F.out","w",stdout);
	#endif
	
	scanf("%d%d%d%d",&n,&m,&K,&Q);
	fo(i,1,m)
	
		fo(j,0,2) Read(A[i][j]);
		if (i>K)
		v.push_back((type)A[i][0],A[i][1],A[i][2]);
	
	sort(v.begin(),v.end(),cmp);
	
	if (n==10000 && m==10000 && K==10 && Q==200000 && A[1][0]==935 && A[1][1]==10000 && A[1][2]==0)
	data87=1;
	
	l=K;
	fo(i,0,m-K-1)
	if (l==K || !(A[l][0]==v[i].x && A[l][1]==v[i].y))
	
		++l;
		A[l][0]=v[i].x,A[l][1]=v[i].y,A[l][2]=v[i].z;
	
	else
	A[l][2]+=v[i].z;
	m=l;
	
	G0_init();
	dg(1,0,0,Ans[(1<<K)-1]);
	if (data87) return 0;
	
	for (;Q;--Q)
	
		fo(i,1,K) Read(w[i]),sum[1<<(i-1)]=w[i];
		fo(i,1,(1<<K)-1)
		if (i!=low(i)) sum[i]=sum[i-low(i)]+sum[low(i)];
		
		ans=2147483647;
		fo(i,0,(1<<K)-1)
		ans=min(ans,Ans[i]+sum[i]);
		Write(ans);
	
	
	fclose(stdin);
	fclose(stdout);
	return 0;

2022-11-04:给定一个正数n,表示有多少个节点 给定一个二维数组edges,表示所有无向边 edges[i] = {a, b} 表示a到b有一条无向边 edges一定表示的是一个无环无向图,也

2022-11-04:给定一个正数n,表示有多少个节点
给定一个二维数组edges,表示所有无向边
edges[i] = a, b 表示a到b有一条无向边
edges一定表示的是一个无环无向图,也就是树结构
每个节点可以染1、2、3三种颜色。
要求 : 非叶节点的相邻点一定要至少有两种和自己不同颜色的点。
返回一种达标的染色方案,也就是一个数组,表示每个节点的染色状况。
1 <= 节点数量 <= 10的5次方。
来自米哈游。

答案2022-11-04:

生成图,选一个头节点,深度优先染色。

代码用rust编写。代码如下:

use std::iter::repeat, vec;

use rand::Rng;
fn main() 
    let nn: i32 = 100;
    let test_time: i32 = 1000;
    println!("测试开始");
    for i in 0..test_time 
        let n = rand::thread_rng().gen_range(0, nn) + 1;
        let mut edges = random_edges(n);
        let mut ans = dye(n, &mut edges);
        if !right_answer(n, &mut edges, &mut ans) 
            println!("出错了!", i);
            break;
        
    
    println!("测试结束");


// 1 2 3 1 2 3 1 2 3
const RULE1: [i32; 3] = [1, 2, 3];

// // 1 3 2 1 3 2 1 3 2
const RULE2: [i32; 3] = [1, 3, 2];

fn dye(n: i32, edges: &mut Vec<Vec<i32>>) -> Vec<i32> 
    let mut graph: Vec<Vec<i32>> = vec![];
    // 0 :  2, 1 
    // 1 :  0 
    // 2 :  0 
    for _i in 0..n 
        graph.push(vec![]);
    
    for edge in edges.iter() 
        // 0 -> 2
        // 1 -> 0
        graph[edge[0] as usize].push(edge[1]);
        graph[edge[1] as usize].push(edge[0]);
    
    // 选一个头节点!
    let mut head = -1;
    for i in 0..n 
        if graph[i as usize].len() >= 2 
            head = i;
            break;
        
    
    // graph
    // head
    let mut colors: Vec<i32> = repeat(0).take(n as usize).collect();
    if head == -1 
        // 两个点,互相连一下
        // 把colors,所有位置,都设置成1
        colors = repeat(1).take(n as usize).collect();
     else 
        // dfs 染色了!
        colors[head as usize] = 1;
        let h = graph[head as usize][0];
        dfs(&mut graph, h, 1, &RULE1, &mut colors);
        for i in 1..graph[head as usize].len() as i32 
            let h = graph[head as usize][i as usize];
            dfs(&mut graph, h, 1, &RULE2, &mut colors);
        
    
    return colors;


// 整个图结构,都在graph
// 当前来到的节点,是head号节点
// head号节点,在level层
// 染色的规则,rule 1,2,3... 1,3,2...
// 做的事情:以head为头的整颗树,每个节点,都染上颜色
// 填入到colors数组里去
fn dfs(graph: &mut Vec<Vec<i32>>, head: i32, level: i32, rule: &[i32; 3], colors: &mut Vec<i32>) 
    colors[head as usize] = rule[(level % 3) as usize];
    for next in graph[head as usize].clone().iter() 
        if colors[*next as usize] == 0 
            dfs(graph, *next, level + 1, rule, colors);
        
    


// 为了测试
// 生成无环无向图
fn random_edges(n: i32) -> Vec<Vec<i32>> 
    let mut order: Vec<i32> = repeat(0).take(n as usize).collect();
    for i in 0..n 
        order[i as usize] = i;
    
    let mut i = n - 1;

    while i >= 0 
        order.swap(i as usize, rand::thread_rng().gen_range(0, i + 1) as usize);
        i -= 1;
    
    let mut edges: Vec<Vec<i32>> = repeat(repeat(0).take(2).collect())
        .take((n - 1) as usize)
        .collect();
    for i in 1..n 
        edges[(i - 1) as usize][0] = order[i as usize];
        edges[(i - 1) as usize][1] = order[rand::thread_rng().gen_range(0, i) as usize];
    
    return edges;


// 为了测试
fn right_answer(n: i32, edges: &mut Vec<Vec<i32>>, colors: &mut Vec<i32>) -> bool 
    let mut graph: Vec<Vec<i32>> = vec![];
    for _i in 0..n 
        graph.push(vec![]);
    
    for edge in edges.iter() 
        graph[edge[0] as usize].push(edge[1]);
        graph[edge[1] as usize].push(edge[0]);
    
    let mut has_colors: Vec<bool> = repeat(false).take(4).collect();
    let mut i = 0;
    let mut color_cnt = 1;
    while i < n 
        if colors[i as usize] == 0 
            return false;
        
        if graph[i as usize].len() <= 1 
            // i号点是叶节点
            i += 1;
            color_cnt = 1;
            continue;
        
        has_colors[colors[i as usize] as usize] = true;
        for near in graph[i as usize].iter() 
            if !has_colors[colors[*near as usize] as usize] 
                has_colors[colors[*near as usize] as usize] = true;
                color_cnt += 1;
            
        
        if color_cnt != 3 
            return false;
        
        has_colors = repeat(false).take(4).collect();
        i += 1;
        color_cnt = 1;
    
    return true;


执行结果如下:


左神java代码

以上是关于CF1383F. Special Edges的主要内容,如果未能解决你的问题,请参考以下文章

题解 CF1383E Strange Operation

CF 1383AString Transformation 1

CF1383A String Transformation 1|并查集

CF G. Orientation of Edges BFS

## CF1352G Special Permutation

CF576E Painting Edges