夯实基础项目工程之图论——Uncle Bogdan and Country Happiness,Graph Coloring,How Many Paths?,Array Differentiation

文章目录

  • 做题情况项目报告
  • Uncle Bogdan and Country Happiness
  • Graph Coloring
  • How Many Paths?
  • Array Differentiation

做题情况项目报告

T1,T3T1,T3T1,T3一眼题,在实现上,T3T3T3耗时略长(有些情况未考虑到位)

T4T4T4感觉题,一眼隐隐约约有正解的思路

T2T2T2感觉题,思考到二分图性质后,并未往DPDPDP上想

Uncle Bogdan and Country Happiness

CD1388C

rating:1800 简单题

给出一颗根节点为111的树,对于每个节点iii,有pip_ipi个人的家在节点iii

一开始所有人都在根节点上,然后每个人会往家沿着最短路走

每个人出发时有一个心情,可能是好心情也可能是坏心情,在经过一条边时,心情可能由好变坏,但是不可能由坏变好

每个点有一个幸福检测器,最后的检测结果为:所有经过该节点的人中,好心情的人数减坏心情的人数

现在给出hih_ihi,问有没有可能最后每个节点的检测结果恰好hih_ihi


solution

observation1 : 这是一棵以111为根的树,经过每个点的人数是固定的,即为子树内居住人数大小,记为sizi\rm siz_isizi

observation2 : 由于心情变化规则可知,父亲的坏心情人数一定不小于直系儿子坏心情人数和

所以直接dfs树一遍,根据good+bad=sizi,good−bad=hi\rm good+bad=siz_i,good-bad=h_igood+bad=sizi,goodbad=hi,可以求得经过每个点时的好坏心情人数,然后根据坏心情人数是否够判断


#include <cstdio>
#include <vector>
using namespace std;
#define maxn 100005
vector < int > G[maxn];
int T, n, m, flag;
int p[maxn], h[maxn], bad[maxn], siz[maxn];void dfs1( int u, int fa ) {siz[u] = p[u];for( auto v : G[u] )if( v == fa ) continue;else dfs1( v, u ), siz[u] += siz[v];bad[u] = ( siz[u] - h[u] ) >> 1;
}void dfs2( int u, int fa ) {int cnt = 0;for( auto v : G[u] ) {if( v == fa ) continue;else dfs2( v, u ), cnt += bad[v];}if( cnt + p[u] < bad[u] ) flag = 1;
}int Fabs( int x ) { return x < 0 ? -x : x; }int main() {scanf( "%d", &T );next :while( T -- ) {scanf( "%d %d", &n, &m );flag = 0;for( int i = 1;i <= n;i ++ )G[i].clear(), siz[i] = bad[i] = 0;for( int i = 1;i <= n;i ++ )scanf( "%d", &p[i] );for( int i = 1;i <= n;i ++ )scanf( "%d", &h[i] );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u );}dfs1( 1, 0 );for( int i = 1;i <= n;i ++ )if( ( ( siz[i] - h[i] ) & 1 ) or ( siz[i] < Fabs( h[i] ) ) ) {printf( "NO\n" );goto next;}dfs2( 1, 0 );if( flag ) printf( "NO\n" );else printf( "YES\n" );}return 0;
}

Graph Coloring

CF1354E

rating 2100: 中档题

现有一张nnn个节点mmm条边的无向图,要求用{1,2,3}\{1,2,3\}{1,2,3}对每个点染色,使得相邻的两个点的权值的绝对值之差刚好111

现在需要求出一个方案,使得一共染了n1n_1n1111n2n_2n2222n3n_3n3333,保证n1+n2+n3=nn_1+n_2+n_3=nn1+n2+n3=n

无解则输出NO\rm NONO;否则输出YES\rm YESYES并输出一个字符串,其中第iii位表示节点iii的颜色


solution

observation1: 各连通块之间互不影响,所以可以分连通块求解

observation2: 1/3只能和2相邻,所以这张图一定是个二分图,并且2一定是全为一种颜色(黑色/白色)

dfs遍历图,判断是否是二分图

至于222必须是同种颜色,分连通块就可以设计dpdpdp转移了

dfs求出连通块黑白颜色的个数及分别是哪些点

dpi,j:dp_{i,j}:dpi,j: 到第iii个连通块被标记222的点数个数为jjj是否存在一种方案可行

dpi,j=dpi−1,j−cnt0,i∣dpi−1,j−cnt1,idp_{i,j}=dp_{i-1,j-cnt_{0,i}}|dp_{i-1,j-{cnt_{1,i}}}dpi,j=dpi1,jcnt0,idpi1,jcnt1,i

只要最后dpcnt,n2=1dp_{cnt,n2}=1dpcnt,n2=1就一定有解

剩下就是很简单的根据dpdpdp倒着回去构造解了,先把所有的222找到,剩下的就是1,31,31,3无所谓了

倒回去看转移的两个dpdpdp哪个是可行的


#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 5005
vector < int > G[maxn], G0[maxn], G1[maxn];
int n, m, n1, n2, n3, cnt;
int c[maxn], ans[maxn];
bool dp[maxn][maxn];
bool vis[maxn], MS[maxn];void dfs1( int u ) {for( auto v : G[u] ) {if( ! ~ c[v] ) {c[v] = c[u] ^ 1;dfs1( v );}else if( c[u] == c[v] ) {printf( "NO\n" );exit( 0 );}}
}void dfs2( int u ) {vis[u] = 1;if( c[u] ) G1[cnt].push_back( u );else G0[cnt].push_back( u );for( auto v : G[u] )if( ! vis[v] ) dfs2( v );
}int main() {scanf( "%d %d %d %d %d", &n, &m, &n1, &n2, &n3 );for( int i = 1, u, v;i <= m;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u );  }memset( c, -1, sizeof( c ) );for( int i = 1;i <= n;i ++ )if( ! ~ c[i] ) c[i] = 0, dfs1( i );for( int i = 1;i <= n;i ++ )if( ! vis[i] ) cnt ++, dfs2( i );dp[0][0] = 1;for( int i = 1;i <= cnt;i ++ )for( int j = 0;j <= n;j ++ ) {if( G0[i].size() <= j )dp[i][j] |= dp[i - 1][j - G0[i].size()];if( G1[i].size() <= j )dp[i][j] |= dp[i - 1][j - G1[i].size()];}if( ! dp[cnt][n2] ) return ! printf( "NO\n" );else printf( "YES\n" );int now = n2;for( int i = cnt;i;i -- ) {if( now >= G0[i].size() and dp[i - 1][now - G0[i].size()] )MS[i] = 0, now -= G0[i].size();else if( dp[i - 1][now - G1[i].size()] )MS[i] = 1, now -= G1[i].size();}for( int i = 1;i <= cnt;i ++ ) if( MS[i] )for( auto j : G1[i] )ans[j] = 2;else for( auto j : G0[i] )ans[j] = 2;for( int i = 1;i <= n;i ++ )if( ! ans[i] ) {if( now < n1 ) ans[i] = 1, now ++;else ans[i] = 3;}for( int i = 1;i <= n;i ++ ) printf( "%d", ans[i] );return 0;
}

How Many Paths?

CF1547G

有一个有向图,图中含有nnn个点mmm条边(边中可能有自环,但是没有重边)

设顶点iii的答案为ansians_iansi,则:

  • 如果不存在一条111iii的路径,ansians_iansi000
  • 如果只存在一条111iii的路径,ansians_iansi111
  • 如果至少存在两条111iii的路径,并且路径数量是有限的,ansians_iansi222
  • 如果存在无限条111iii的路径,ansians_iansi−1-11

注意路径不必是简单路径

对于每一个1≤i≤n1 \leq i \leq n1in,输出ansians_iansi


observation1: 不必是简单路径,所以可以到处绕弯

observation2: 只要存在一条路上有环,那么到iii的路径就一定是无线条

自环特殊记录一下

tarjan缩点,对缩点后的状态建图,同一个连通块内的边不再出现

连通块内点数>1>1>1或者有自环标记说明该连通块是环,连出去的边,边权−1-11;否则边权000

111所在的连通块scc[1]开始跑堆优化dijkstra最短路

并记录经过iii的次数vis[i]

如果iii的路径长为inf证明到达不了,没有路径

如果路径长为负数,说明有至少一条路径上有环,则是无限条路径

堆优化dijkstra最短路记录经过次数后,直接判断是否>1>1>1是不对的

因为写法会导致,多次经过某点时,若没有最短路更新是不会入队,也就不会使得后面的点的经过次数增加

也就是说经过次数其实维护的是假的

在记录一个pre[i]表示最短路iiipreipre_iprei更新

最后倒着往前面找,然后vis[i]取一路上的最大值

这样虽然维护的还是假的真正经过次数,但是就已经可以区别出是只经过一次还是更多次,我们也没有必要找到真正经过了多少次iii

#include <stack>
#include <queue>
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 400005
struct node {int to, w;node(){}node( int To, int W ) {	to = To, w = W; }bool operator < ( const node &t ) const { return w > t.w; }
};
struct edge {int u, v;edge(){}edge( int U, int V ) { u = U, v = V; }
}E[maxn];
priority_queue < node > q;
stack < int > sta;
vector < node > g[maxn];
vector < int > G[maxn], cnt[maxn];
int T, n, m, ip, tot;
int dfn[maxn], low[maxn], dis[maxn], vis[maxn], scc[maxn], cir[maxn], pre[maxn], gone[maxn];void tarjan( int u ) {dfn[u] = low[u] = ++ ip, sta.push( u );for( auto v : G[u] ) {if( ! dfn[v] ) { tarjan( v ); low[u] = min( low[u], low[v] ); }else if( ! scc[v] ) low[u] = min( low[u], dfn[v] );}if( low[u] == dfn[u] ) {++ tot; int v;do {v = sta.top(), sta.pop(), scc[v] = tot;cnt[tot].push_back( v );} while( v != u );}
}void find( int i ) {if( ! i or gone[i] ) return;else gone[i] = 1, find( pre[i] ), vis[i] = max( vis[i], vis[pre[i]] );
}int main() {scanf( "%d", &T );int Case;while( T -- ) {scanf( "%d %d", &n, &m );ip = tot = 0;while( ! q.empty() ) q.pop();while( ! sta.empty() ) sta.pop();for( int i = 1;i <= n;i ++ ) {cnt[i].clear(), G[i].clear(), g[i].clear();dfn[i] = vis[i] = cir[i] = scc[i] = gone[i] = pre[i] = 0, dis[i] = inf;}int Edge = 0;for( int i = 1, u, v;i <= m;i ++ ) {scanf( "%d %d", &u, &v );if( u == v ) cir[u] = 1;else G[u].push_back( v ), E[++ Edge] = edge( u, v );}for( int i = 1;i <= n;i ++ )if( ! dfn[i] ) tarjan( i );for( int i = 1;i <= Edge;i ++ )if( scc[E[i].u] ^ scc[E[i].v] ) {if( cir[E[i].u] or cir[E[i].v] or cnt[scc[E[i].u]].size() > 1 or cnt[scc[E[i].v]].size() > 1 )g[scc[E[i].u]].push_back( node( scc[E[i].v], -1 ) );elseg[scc[E[i].u]].push_back( node( scc[E[i].v], 0 ) );}dis[scc[1]] = cnt[scc[1]].size() > 1 ? -1 : 0;q.push( node( scc[1], 0 ) );vis[scc[1]] ++;while( ! q.empty() ) {int u = q.top().to; q.pop();for( int i = 0;i < g[u].size();i ++ ) {int v = g[u][i].to, w = g[u][i].w;vis[v] ++;if( dis[v] < 0 ) continue; if( dis[u] + w < dis[v] ) {dis[v] = dis[u] + w, pre[v] = u;q.push( node( v, dis[v] ) );}}}gone[scc[1]] = 1;for( int i = 1;i <= tot;i ++ ) find( i );for( int i = 1;i <= n;i ++ )if( dis[scc[i]] == inf ) printf( "0 " );else if( dis[scc[i]] < 0 or cir[i] or cnt[scc[i]].size() > 1 ) printf( "-1 " );else if( vis[scc[i]] > 1 ) printf( "2 " );else printf( "1 " );printf( "\n" );}return 0;
}

Array Differentiation

CF1552D

ttt组数据,每一组给定一个数组{an}\{a_n\}{an},问是否存在这样一个数组{bn}\{ b_n \}{bn},对于所有i∈[1,n]i \in [1,n]i[1,n],都存在一组j、k∈[1,n]j、k\in[1,n]jk[1,n],满足ai=bj−bka_i=b_j-b_kai=bjbk

1<=n<=10


solution

如果把bib_ibi当成点权,建构一棵树,使得aja_jaj恰好等于树上的边权

那么最后剩下的aja_jaj就会使得树变成一张图,并不是一个环,因为这是有向边

但是如果这其中的某些边取反,似乎就能成为一个环

nnn的范围那么小基本锁定正解就是3n3^n3n暴搜,取反某些aia_iai的值−ai-a_iai,然后存在某些aaa的和为000


#include <cstdio>
#include <algorithm>
using namespace std;
int T, n, flag;
int a[15];void dfs( int x, int sum, int cnt ) {if( sum == 0 and cnt ) {flag = 0;return;}if( x > n ) return;if( flag ) dfs( x + 1, sum, cnt );if( flag ) dfs( x + 1, sum + a[x], cnt + 1 );if( flag ) dfs( x + 1, sum - a[x], cnt + 1 );
}int main() {scanf( "%d", &T );next :while( T -- ) {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )scanf( "%d", &a[i] );sort( a + 1, a + n + 1 );for( int i = 1;i < n;i ++ )if( a[i] == a[i + 1] ) {printf( "YES\n" );goto next;}n = unique( a + 1, a + n + 1 ) - a - 1;flag = 1;dfs( 1, 0, 0 );if( flag ) printf( "NO\n" );else printf( "YES\n" );}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317224.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Codeforces Round #716 (Div. 2)

Codeforces Round #716 (Div. 2) CodeForces 1514 题号题目知识点难度APerfectly Imperfect ArrayBAND 0, Sum BigCProduct 1 Modulo NDCut and StickEBaby Ehab’s Hyper Apartment

用StyleCop规范团队代码

前言编码风格&#xff0c;每个人都是有不同的特点&#xff0c;风格各异&#xff0c;而且一个人在不同的时期&#xff0c;编码风格的差异也可能是非常大的&#xff0c;好比学生时代&#xff0c;刚工作的时候&#xff0c;工作一段时间后等。在一个团队中&#xff0c;或一个项目中…

CodeForces:103(div1)104(div2)

文章目录前言CF104A BlackjackDescription\text{Description}DescriptionSolution\text{Solution}SolutionCode\text{Code}CodeCF103A Testing Pants for SadnessDescription\text{Description}DescriptionSolution\text{Solution}SolutionCode\text{Code}CodeCF103B CthulhuDe…

UOJ#749-[UNR #6]稳健型选手【贪心,分治,主席树】

正题 题目链接:https://uoj.ac/problem/749 题目大意 如果有序列aaa&#xff0c;你每次取走一个数字后然后这个序列最前面的数字会被别人取走&#xff0c;直到序列为空。此时f(a)f(a)f(a)表示你最大能取走的权值和。 给出一个长度为nnn的序列aaa&#xff0c;qqq次询问区间[l…

A. And Then There Were K

A. And Then There Were K 题意&#xff1a; 给你一个n&#xff0c;让你求一个k&#xff0c;使得满足下列式子&#xff1a; n & (n-1) & (n-2) &…&(k) 0 问k最小是多少&#xff1f; 题解&#xff1a; 找规律 比如n的二进制为&#xff1a;1111 那么n-1就是…

一键发布部署vs插件[AntDeploy],让net开发者更幸福

一键发布工具(ant deploy tool)插件下载地址&#xff1a;https://marketplace.visualstudio.com/items?itemNamenainaigu.AntDeploy1.iis一键发布自动部署 (iis deploy support)支持netcore 和 netframework发布 (支持mvc webapi)支持website自动创建ps:需要在windows 服务器上…

数据结构二之线段树Ⅰ——Count Color,Hotel,Transformation,Tree Generator™

普通的下标线段树Count ColorHotelTransformationTree Generator™Count Color POJ2777 查询区间内颜色种类数&#xff0c;观察到颜色种类数只有30&#xff0c;完全可以状压成整型存储&#xff0c;没有必要开30棵线段树 区间内有这颜色就置为111&#xff0c;没有这个颜色就是…

计算几何全家桶

文章目录前言精度点/向量相关表示向量基本运算角度相关向量夹角旋转直线/线段相关表示点与线求点到直线垂足求点关于直线的对称点点与直线的位置关系点与直线的距离线与线直线与直线的位置关系共线与垂直判断线段与线段是否相交求直线与直线的交点角平分线中垂线多边形表示求多…

uoj#750-[UNR #6]小火车【二分,折半,鸽笼原理】

正题 题目链接:https://uoj.ac/problem/750 题目大意 给出nnn个数字和一个ppp&#xff0c;保证2n>p2^n> p2n>p。现在要求一个序列www满足wi∈[−1,1]w_i\in[-1,1]wi​∈[−1,1]&#xff0c;使得∑i1nwiai≡0(modp)\sum_{i1}^nw_ia_i\equiv 0\pmod p∑i1n​wi​ai​≡…

Sequence Pair Weight

Sequence Pair Weight 题意&#xff1a; 一个数组a&#xff0c;其中两个一样的数的贡献为1&#xff0c;问这个数组的所有子串的贡献和是多少? 题解&#xff1a; 举例&#xff1a; 对于[1&#xff0c;2&#xff0c;1&#xff0c;2&#xff0c;1&#xff0c;1&#xff0c;4]…

什么是量子计算机?用一个简单例子来解释

译者&#xff1a;王亮 作者&#xff1a;YK Sugi 原文&#xff1a;http://t.cn/EZAElk0Hi&#xff0c;大家好&#xff01;不久前&#xff0c;我参观了加拿大温哥华的D-Wave Systems公司&#xff0c;这是一家制造前沿量子计算机的公司。我在那里学到了很多关于量子计算机的知识&a…

CodeForces616:Educational Round 5

文章目录前言A Comparing Two Long Integers\text{A Comparing Two Long Integers}A Comparing Two Long IntegersDescription\text{Description}DescriptionSolution\text{Solution}SolutionCode\text{Code}CodeB Dinner with Emma\text{B Dinner with Emma}B Dinner with Emm…

CF1534F2-Falling Sand (Hard Version)

正题 题目链接:https://www.luogu.com.cn/problem/CF1534F2 题目大意 有一个n∗mn*mn∗m个网格&#xff0c;有的网格上有沙子&#xff0c;一个沙子被刷新后会下落到底并且刷新沿途中四周四连通的沙子&#xff0c;你可以选择一些沙子手动刷新。 现在要求第iii列至少有aia_iai…

数据结构二之线段树Ⅱ——KiKi‘s K-Number,ball,The Child and Sequence,「雅礼集训 2017 Day1」市场,Atlantis

值域线段树势能线段树扫描线KiKis K-NumberballThe Child and Sequence「雅礼集训 2017 Day1」市场AtlantisKiKi’s K-Number HDU-2852 权值线段树维护插入删除很简单 对于查询大于xxx的第kkk个&#xff0c;可以不用二分&#xff0c;转化一下 先查小于等于xxx的个数cntcntc…

Codeforces Round #721 (Div. 2)

Codeforces Round #721 (Div. 2) 题号题目难度知识点AAnd Then There Were KBPalindrome Game (easy version)CPalindrome Game (hard version)DSequence Pair WeightEMEX TreeFPartition Game

解决Azure DevOps部署到Azure后.NET Core网站无法启动的问题

点击上方蓝字关注“汪宇杰博客”最近我遭遇了一个奇怪的问题。使用Azure DevOps配置CI/CD管线&#xff0c;自动部署到Azure App Service以后&#xff0c;.NET Core的网站竟然会启动失败。我们来看看如何解决这个问题。查找问题首先&#xff0c;幸好&#xff0c;这是个staging环…

CF1286E-Fedya the Potter Strikes Back【KMP,RMQ】

正题 题目链接:https://www.luogu.com.cn/problem/CF1286E 题目大意 定义一个字符串sss的权值为对于每个sL∼Rs1∼R−L1s_{L\sim R}s_{1\sim R-L1}sL∼R​s1∼R−L1​的区间&#xff0c;会产生min⁡iLRwi\min_{iL}^Rw_iminiLR​wi​的贡献。 现在开始时sss为空串&#xff0c…

模板:二维凸包(计算几何)

所谓凸包&#xff0c;就是一个凸出来的包 &#xff08;逃&#xff09; 前言 计算集合的第一课。 关键特征&#xff1a;周长最小。此时一定是凸包。 解析 定义 凸包&#xff1a;在平面上能包含所有给定点的最小凸多边形叫做凸包。 性质&#xff1a;凸包的周长是所有能包含给…

[AtCoder Beginner Contest 215] A-G题解

文章目录A - Your First JudgeB - log2(N)C - One More aab aba baaD - Coprime 2E - Chain ContestantF - Dist Max 2G - Colorful Candies 2atcoder题目链接 A - Your First Judge 签到题 #include <cstdio> #include <iostream> using namespace std; string…

Acwing 135 最大子序和

Acwing 135 最大子序和 题目&#xff1a; 输入一个长度为 n 的整数序列&#xff0c;从中找出一段长度不超过 m 的连续子序列&#xff0c;使得子序列中所有数的和最大。 题解&#xff1a; 我们把这个问题的集合分成n份&#xff0c;第k份表示以A[k]结尾的最大连续子序列是多少…