文章目录
1、不要62(数位DP)
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
Input
输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。
Output
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
Sample Input
1 100
0 0
Sample Output
80
解析:
可以看到n的数据范围特别大,暴力求解肯定会TLE,这时候就要用到数位dp。
数位dp是一种计数用的dp,一般就是要统计一个区间[le,ri]内满足一些条件数的个数。所谓数位dp,字面意思就是在数位上进行dp。数位的含义:一个数有个位、十位、百位、千位…数的每一位就是数位。
数位dp的实质就是换一种暴力枚举的方式,使得新的枚举方式满足dp的性质,然后记忆化就可以了。
long long dp[i][status]表示第i位 当前状态为status的数一共有多少个,在本题中,因为4只有一位,可以在遍历的过程中直接删掉,所以不作考虑,而前一位取6的话后一位则不能取2,则这里status有两种状态,表示前一位是6和前一位不是6,是6则为1不是6则为0,那么dp[3][1]就表示x000到x999,x不为6,有几个满足条件的数,dp[1][0]就表示x0-x9,x不为6的个数。
还要加上特判条件:那么如果有前导0,或者遍历0-9的时候有上界的要求时,就不能使用记忆化搜索。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<iomanip>
using namespace std;
long long dp[20][2];
int m[20];//最上面要加上你定义的a数组和dp数组。。。
long long dfs(int pos,bool limit,bool lead,bool status )
{
if(pos==-1)return 1;
if(limit==false&&lead==false&&dp[pos][status]!=-1)return dp[pos][status];
//意思是没有上界和前导0的限制的时候,可以使用记忆化搜索
int up=limit?m[pos]:9;
//如果有上界的限制,那这一位只能取到a[pos],不然可以取到9
long long ans=0;
for(int i=0;i<=up;i++){
//枚举每一位取什么
if(i==4)continue;
if(status&&i==2)continue;
ans+=dfs(pos-1,limit&&i==m[pos],lead&&i==0,i==6);
//)//往下递归 获得结果 当前这一位选了i肯定会对下一位有影响。
}
if(limit==false&&lead==false)//没有上界和前导零的限制可以使用记忆化搜索
dp[pos][status]=ans;
return ans;
}
long long solver(int x){
int pos=-1;
while(x){
pos++;
m[pos]=x%10;
x/=10;
}
return dfs(pos,1,1,0);
}
int main() {
long long a,b;
memset(dp,-1,sizeof(dp));
//数位dp第一件事 先在main函数里面把dp数组置为-1,千万千万别忘了,因为dp[i][j]==0表示i位状态位j的数有0个 而dp[i][j]==-1表示这种情况没有讨论过需要走一遍
while(cin>>a>>b&&a||b){
cout<<solver(b)-solver(a-1)<<endl;
}
}
2、Number Of Ways
You’ve got array a[1], a[2], …, a[n], consisting of n integers. Count the number of ways to split all the elements of the array into three contiguous parts so that the sum of elements in each part is the same.
More formally, you need to find the number of such pairs of indices i, j (2 ≤ i ≤ j ≤ n - 1), that .
Input
The first line contains integer n (1 ≤ n ≤ 5·105), showing how many numbers are in the array. The second line contains n integers a[1], a[2], …, a[n] (|a[i]| ≤ 109) — the elements of array a.
Output
Print a single integer — the number of ways to split the array into three parts with the same sum.
Examples
Input
5
1 2 3 0 3
Output
2
Input
4
0 1 -1 0
Output
1
Input
2
4 1
Output
0
#include <cstdio>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;
long long a[5 * 100000];
int main()
{
int n;
long long x;
long long sum=0;
while (cin >> n)
{
cin >> a[0];
for (int i = 1; i < n; i++)
{
cin >> x;
a[i] = a[i - 1] + x;
}
if (a[n - 1] % 3 != 0)
{
cout << 0 << endl;
continue;
}
int m=0;
for (int i = 0; i < n - 1; i++)
{
if (a[i] == a[n - 1] / 3 * 2)
sum+=m;
if (a[i] == a[n - 1] / 3)
m++;
}
cout << sum << endl;
}
return 0;
}
3、Queue
During the lunch break all n Berland State University students lined up in the food court. However, it turned out that the food court, too, has a lunch break and it temporarily stopped working.
Standing in a queue that isn’t being served is so boring! So, each of the students wrote down the number of the student ID of the student that stands in line directly in front of him, and the student that stands in line directly behind him. If no one stands before or after a student (that is, he is the first one or the last one), then he writes down number 0 instead (in Berland State University student IDs are numerated from 1).
After that, all the students went about their business. When they returned, they found out that restoring the queue is not such an easy task.
Help the students to restore the state of the queue by the numbers of the student ID’s of their neighbors in the queue.
Input
The first line contains integer n (2 ≤ n ≤ 2·105) — the number of students in the queue.
Then n lines follow, i-th line contains the pair of integers ai, bi (0 ≤ ai, bi ≤ 106), where ai is the ID number of a person in front of a student and bi is the ID number of a person behind a student. The lines are given in the arbitrary order. Value 0 is given instead of a neighbor’s ID number if the neighbor doesn’t exist.
The ID numbers of all students are distinct. It is guaranteed that the records correspond too the queue where all the students stand in some order.
Output
Print a sequence of n integers x1, x2, …, xn — the sequence of ID numbers of all the students in the order they go in the queue from the first student to the last one.
Examples
Input
4
92 31
0 7
31 0
7 141
Output
92 7 31 141
Note
The picture illustrates the queue for the first sample.
解析:
将给的数据分为奇数位和偶数位来排。。用next[]来存后继,pre[]存前驱。再用一个flag[]标记. 每次读入两个数 a,b 让next[a] = b,pre[b] = a ,flag [a] = flag[b] = 1;然后让next从0开始扫一遍就能得到处在偶数位置的数。每次访问后将flag[]置0。 接下来找奇数位置的数。扫一遍flag 直到遇到flag[i]的值为1的时候退出循环。然后tmp = i ,然后从tmp开始扫一遍pre找到第一个位置的数,然后就可以填满奇数位置的数了。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define M 200010
const int N = 1000010;
int main ()
{
int i;
int next[N];
int pre[N];
int ans[M];
int flag[N];
int n;
memset(next,-1,sizeof(next));
memset(pre,-1,sizeof(pre));
memset(ans,0,sizeof(ans));
memset(flag,0,sizeof(flag));
scanf("%d",&n);
for(i=1;i<=n;i++){
int a,b;
scanf("%d%d",&a,&b);
next[a] = b;
pre[b] = a;
flag[a] = 1;
flag[b] = 1;
}
int tmp=0,k=2;
while(1){
ans[k] = next[tmp];
flag[ans[k]] = 0;
k += 2;
tmp = next[tmp];
if(tmp<=0) break;
}
int cnt;
for(i=1;i<=1000000;i++){
if(flag[i]){
cnt = i;
break;
}
}
tmp = cnt;
while(1){
if(pre[tmp]<0) break;
tmp = pre[tmp];
}
k = 1;
while(1){
ans[k] = tmp;
k += 2;
tmp = next[tmp];
if(tmp<=0) break;
}
for(i=1;i<=n;i++){
printf("%d ",ans[i]);
}
return 0;
}
4、 Sushi for Two
Arkady invited Anna for a dinner to a sushi restaurant. The restaurant is a bit unusual: it offers n
pieces of sushi aligned in a row, and a customer has to choose a continuous subsegment of these sushi to buy.
The pieces of sushi are of two types: either with tuna or with eel. Let’s denote the type of the i
-th from the left sushi as ti, where ti=1 means it is with tuna, and ti=2
means it is with eel.
Arkady does not like tuna, Anna does not like eel. Arkady wants to choose such a continuous subsegment of sushi that it has equal number of sushi of each type and each half of the subsegment has only sushi of one type. For example, subsegment [2,2,2,1,1,1]
is valid, but subsegment [1,2,1,2,1,2]
is not, because both halves contain both types of sushi.
Find the length of the longest continuous subsegment of sushi Arkady can buy.
Input
The first line contains a single integer n
(2≤n≤100000
) — the number of pieces of sushi.
The second line contains n
integers t1, t2, …, tn (ti=1, denoting a sushi with tuna or ti=2
, denoting a sushi with eel), representing the types of sushi from left to right.
It is guaranteed that there is at least one piece of sushi of each type. Note that it means that there is at least one valid continuous segment.
Output
Print a single integer — the maximum length of a valid continuous segment.
Examples
Input
7
2 2 2 1 1 2 2
Output
4
Input
6
1 2 1 2 1 2
Output
2
Input
9
2 2 1 1 1 2 2 2 2
Output
6
Note
In the first example Arkady can choose the subsegment [2,2,1,1]
or the subsegment [1,1,2,2] with length 4
.
In the second example there is no way but to choose one of the subsegments [2,1]
or [1,2] with length 2
.
In the third example Arkady’s best choice is the subsegment [1,1,1,2,2,2]
5、even substring
You are given a string s=s1s2…sn of length n, which only contains digits 1, 2, …, 9
A substring s[l…r]
of s is a string slsl+1sl+2…sr. A substring s[l…r] of s
is called even if the number represented by it is even.
Find the number of even substrings of s
. Note, that even if some substrings are equal as strings, but have different l and r , they are counted as different substrings.
Input
The first line contains an integer n
(1≤n≤65000) — the length of the string s.
The second line contains a string s
of length n. The string s consists only of digits 1, 2, …, 9 .
Output
Print the number of even substrings of s
.
Examples
Input
4
1234
Output
6
Input
4
2244
Output
10
Note
In the first example, the [l,r]
pairs corresponding to even substrings are:
s[1…2]
s[2…2]
s[1…4]
s[2…4]
s[3…4]
s[4…4]
In the second example, all 10
substrings of s are even substrings. Note, that while substrings s[1…1] and s[2…2] both define the substring “2”, they are still counted as different substrings.
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int main(){
int n;
int sum=0;
cin>>n;
char ss[65005];
for(int i=0;i<n;i++)
{ cin>>ss[i];
if((ss[i]-'0')%2==0)
sum=sum+i+1;
}
cout<<sum<<endl;
return 0;
}
6、Nastya is Reading a Book
After lessons Nastya decided to read a book. The book contains n
chapters, going one after another, so that one page of the book belongs to exactly one chapter and each chapter contains at least one page.
Yesterday evening Nastya did not manage to finish reading the book, so she marked the page with number k
as the first page which was not read (i.e. she read all pages from the 1-st to the (k−1) -th).
The next day Nastya’s friend Igor came and asked her, how many chapters remain to be read by Nastya? Nastya is too busy now, so she asks you to compute the number of chapters she has not completely read yet (i.e. the number of chapters she has not started to read or has finished reading somewhere in the middle).
Input
The first line contains a single integer n
(1≤n≤100
) — the number of chapters in the book.
There are n
lines then. The i-th of these lines contains two integers li, ri separated by space (l1=1, li≤ri) — numbers of the first and the last pages of the i-th chapter. It’s guaranteed that li+1=ri+1 for all 1≤i≤n−1, and also that every chapter contains at most 100
pages.
The (n+2)
-th line contains a single integer k (1≤k≤rn
) — the index of the marked page.
Output
Print a single integer — the number of chapters which has not been completely read so far.
Examples
Input
3
1 3
4 7
8 11
2
Output
3
Input
3
1 4
5 9
10 12
9
Output
2
Input
1
1 7
4
Output
1
Note
In the first example the book contains 11
pages and 3 chapters — [1;3], [4;7] and [8;11]. Nastya marked the 2-nd page, so she finished in the middle of the 1-st chapter. So, all chapters has not been read so far, so the answer is 3
The book in the second example contains 12
pages and 3 chapters too, but Nastya finished reading in the middle of the 2-nd chapter, so that the answer is 2.
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int n,i,k;
cin>>n;
int ss[110],ee[110];
for(i=1;i<=n;i++)
{
cin>>ss[i]>>ee[i];
}
cin>>k;
for(int i=1;i<=n;i++)
{
if(k>=ss[i]&&k<=ee[i])
cout<<n+1-i<<endl;
}
return 0;
}
7、Water Buying
Polycarp wants to cook a soup. To do it, he needs to buy exactly n
liters of water.
There are only two types of water bottles in the nearby shop — 1
-liter bottles and 2
-liter bottles. There are infinitely many bottles of these two types in the shop.
The bottle of the first type costs a
burles and the bottle of the second type costs b
burles correspondingly.
Polycarp wants to spend as few money as possible. Your task is to find the minimum amount of money (in burles) Polycarp needs to buy exactly n
liters of water in the nearby shop if the bottle of the first type costs a burles and the bottle of the second type costs b
burles.
You also have to answer q
independent queries.
Input
The first line of the input contains one integer q
(1≤q≤500) — the number of queries.
The next n
lines contain queries. The i-th query is given as three space-separated integers ni, ai and bi (1≤ni≤1012,1≤ai,bi≤1000) — how many liters Polycarp needs in the i-th query, the cost (in burles) of the bottle of the first type in the i-th query and the cost (in burles) of the bottle of the second type in the i
-th query, respectively.
Output
Print q
integers. The i-th integer should be equal to the minimum amount of money (in burles) Polycarp needs to buy exactly ni liters of water in the nearby shop if the bottle of the first type costs ai burles and the bottle of the second type costs bi
burles.
Example
Input
4
10 1 3
7 3 2
1 1000 1
1000000000000 42 88
Output
10
9
1000
42000000000000
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
int main(){
ll int n,m,k,l,i,sum;
cin>>n;
for(i=0;i<n;i++)
{
sum=0;
cin>>m>>k>>l;
if(m%2)
{sum+=k;m--;
}
if(2*k>l)
{
sum+=((m) / 2)*l;
}
else{
sum+=m*k;
}
cout<<sum<<endl;
}
return 0;
}
8、拓扑排序(1)
描述
由于今天上课的老师讲的特别无聊,小Hi和小Ho偷偷地聊了起来。
小Ho:小Hi,你这学期有选什么课么?
小Hi:挺多的,比如XXX1,XXX2还有XXX3。本来想选YYY2的,但是好像没有先选过YYY1,不能选YYY2。
小Ho:先修课程真是个麻烦的东西呢。
小Hi:没错呢。好多课程都有先修课程,每次选课之前都得先查查有没有先修。教务公布的先修课程记录都是好多年前的,不但有重复的信息,好像很多都不正确了。
小Ho:课程太多了,教务也没法整理吧。他们也没法一个一个确认有没有写错。
小Hi:这不正是轮到小Ho你出马的时候了么!
小Ho:哎??
我们都知道大学的课程是可以自己选择的,每一个学期可以自由选择打算学习的课程。唯一限制我们选课是一些课程之间的顺序关系:有的难度很大的课程可能会有一些前置课程的要求。比如课程A是课程B的前置课程,则要求先学习完A课程,才可以选择B课程。大学的教务收集了所有课程的顺序关系,但由于系统故障,可能有一些信息出现了错误。现在小Ho把信息都告诉你,请你帮小Ho判断一下这些信息是否有误。错误的信息主要是指出现了"课程A是课程B的前置课程,同时课程B也是课程A的前置课程"这样的情况。当然"课程A是课程B的前置课程,课程B是课程C的前置课程,课程C是课程A的前置课程"这类也是错误的。
提示:拓扑排序
小Ho拿出纸笔边画边说道:如果把每一门课程看作一个点,那么顺序关系也就是一条有向边了。错误的情况也就是出现了环。我知道了!这次我们要做的是判定一个有向图是否有环。
小Ho:这个问题可以这样来解决:
-
计算每一个点的入度值deg[i],这一步需要扫描所有点和边,复杂度O(N+M)。
-
把入度为0的点加入队列Q中,当然有可能存在多个入度为0的点,同时它们之间也不会存在连接关系,所以按照任意顺序加入Q都是可以的。
-
从Q中取出一个点p。对于每一个未删除且与p相连的点q,deg[q] = deg[q] - 1;如果deg[q]==0,把q加入Q。
-
不断重复第3步,直到Q为空。
最后剩下的未被删除的点,也就是组成环的点了。
小Hi:没错。这一过程就叫做拓扑排序。
小Ho:我懂了。我这就去实现它!
< 十分钟之后 >
小Ho:小Hi,不好了,我的程序写好之后编译就出诡异错误了!
小Hi:诡异错误?让我看看。
小Hi凑近电脑屏幕看了看小Ho的源代码,只见小Ho写了如下的代码:
int edge[ MAXN ][ MAXN ];
小Hi:小Ho,你有理解这题的数据范围么?
小Ho:N最大等于10万啊,怎么了?
小Hi:你的数组有10万乘上10万,也就是100亿了。算上一个int为4个字节,这也得400亿字节,将近40G了呢。
小Ho:啊?!那我应该怎么?QAQ
小Hi:这里就教你一个小技巧好了:
这道题目中N的数据范围在10万,若采用邻接矩阵的方式来储存数据显然是会内存溢出。而且每次枚举一个点时也可能会因为枚举过多无用的而导致超时。因此在这道题目中我们需要采用邻接表的方式来储存我们的数据:
常见的邻接表大多是使用的指针来进行元素的串联,其实我们可以通过数组来模拟这一过程。
int head[ MAXN + 1] = {0}; // 表示头指针,初始化为0
int p[ MAXM + 1]; // 表示指向的节点
int next[ MAXM + 1] = {0}; // 模拟指针,初始化为0
int edgecnt; // 记录边的数量
void addedge(int u, int v) { // 添加边(u,v)
++edgecnt;
p[ edgecnt ] = v;
next[ edgecnt ] = head[u];
head[u] = edgecnt;
}
// 枚举边的过程,u为起始点
for (int i = head[u]; i; i = next[i]) {
v = p[i];
…
}
输入
第1行:1个整数T,表示数据的组数T(1 <= T <= 5)
接下来T组数据按照以下格式:
第1行:2个整数,N,M。N表示课程总数量,课程编号为1…N。M表示顺序关系的数量。1 <= N <= 100,000. 1 <= M <= 500,000
第2…M+1行:每行2个整数,A,B。表示课程A是课程B的前置课程。
输出
第1…T行:每行1个字符串,若该组信息无误,输出"Correct",若该组信息有误,输出"Wrong"。
Sample Input
2
2 2
1 2
2 1
3 2
1 2
1 3
Sample Output
Wrong
Correct
#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
const int N=5*1e5+10;
int t,n,m;
int indegree[N];
vector <int >vec[N];
bool topsort()
{
queue<int >q;
for(int i=1; i<=n; i++)
if(indegree[i]==0) q.push(i);
int ans=0,sum=0;
while(!q.empty())
{
int u=q.front();
q.pop();
sum++;
for(int i=0; i<vec[u].size(); i++)
{
int temp=vec[u][i];
if(--indegree[temp]==0) q.push(temp);
}
}
if(sum<n) return false;//判断拓扑排序
return true;
}
int main()
{
int u,v,a;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(indegree,0,sizeof(indegree));
for(int i=1; i<=n; i++) if(vec[i].size()) vec[i].clear();
while(m--)
{
scanf("%d%d",&v,&u);
vec[v].push_back(u);
indegree[u]++;
}
if(topsort()) puts("Correct");
else puts("Wrong");
}
return 0;
}
9、拓扑排序(2)
描述
小Hi和小Ho所在学校的校园网被黑客入侵并投放了病毒。这事在校内BBS上立刻引起了大家的讨论,当然小Hi和小Ho也参与到了其中。从大家各自了解的情况中,小Hi和小Ho整理得到了以下的信息:
校园网主干是由N个节点(编号1…N)组成,这些节点之间有一些单向的网路连接。若存在一条网路连接(u,v)链接了节点u和节点v,则节点u可以向节点v发送信息,但是节点v不能通过该链接向节点u发送信息。
在刚感染病毒时,校园网立刻切断了一些网络链接,恰好使得剩下网络连接不存在环,避免了节点被反复感染。也就是说从节点i扩散出的病毒,一定不会再回到节点i。
当1个病毒感染了节点后,它并不会检查这个节点是否被感染,而是直接将自身的拷贝向所有邻居节点发送,它自身则会留在当前节点。所以一个节点有可能存在多个病毒。
现在已经知道黑客在一开始在K个节点上分别投放了一个病毒。
举个例子,假设切断部分网络连接后学校网络如下图所示,由4个节点和4条链接构成。最开始只有节点1上有病毒。
week48_1.png
最开始节点1向节点2和节点3传送了病毒,自身留有1个病毒:
week48_2.png
其中一个病毒到达节点2后,向节点3传送了一个病毒。另一个到达节点3的病毒向节点4发送自己的拷贝:
week48_3.png
当从节点2传送到节点3的病毒到达之后,该病毒又发送了一份自己的拷贝向节点4。此时节点3上留有2个病毒:
week48_4.png
最后每个节点上的病毒为:
week48_5.png
小Hi和小Ho根据目前的情况发现一段时间之后,所有的节点病毒数量一定不会再发生变化。那么对于整个网络来说,最后会有多少个病毒呢?
输入
第1行:3个整数N,M,K,1≤K≤N≤100,000,1≤M≤500,000
第2行:K个整数A[i],A[i]表示黑客在节点A[i]上放了1个病毒。1≤A[i]≤N
第3…M+2行:每行2个整数 u,v,表示存在一条从节点u到节点v的网络链接。数据保证为无环图。1≤u,v≤N
输出
第1行:1个整数,表示最后整个网络的病毒数量 MOD 142857
Sample Input
4 4 1
1
1 2
1 3
2 3
3 4
Sample Output
6
#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 5 * 1e5 + 10;
const int MOD = 142857;
int k, n, m;
int indegree[N];
int virus[N];
vector <int >vec[N];
void topsort()
{
int sum = 0;
queue<int >q;
for (int i = 1; i <= n; i++)
if (indegree[i] == 0) q.push(i);
while (!q.empty())
{
int u = q.front();
q.pop();
sum += virus[u];
sum%=MOD;
//cout << virus[u] << " ";
for (int i = 0; i<vec[u].size(); i++)
{
int temp = vec[u][i];
virus[temp] += virus[u];
virus[temp] %= MOD;
if (--indegree[temp] == 0) q.push(temp);
}
}
cout << sum << endl;
}
int main()
{
int d,u,v;
cin >> n >> m >> k;
memset(virus, 0, sizeof(virus));
while (k--)
{
cin >> d;
virus[d]++;
//cout << d<<endl;
//cout << virus[d] << endl;
}
memset(indegree, 0, sizeof(indegree));
for (int i = 1; i <= n; i++) if (vec[i].size()) vec[i].clear();
while (m--)
{
cin>>u>>v;
vec[u].push_back(v);//v在u后
indegree[v]++;
}
topsort();
return 0;
}
10、二分图
描述
大家好,我是小Hi和小Ho的小伙伴Nettle,从这个星期开始由我来完成我们的Weekly。
新年回家,又到了一年一度大龄剩男剩女的相亲时间。Nettle去姑姑家玩的时候看到了一张姑姑写的相亲情况表,上面都是姑姑介绍相亲的剩男剩女们。每行有2个名字,表示这两个人有一场相亲。由于姑姑年龄比较大了记性不是太好,加上相亲的人很多,所以姑姑一时也想不起来其中有些人的性别。因此她拜托我检查一下相亲表里面有没有错误的记录,即是否把两个同性安排了相亲。
OK,让我们愉快的暴力搜索吧!
才怪咧。
对于拿到的相亲情况表,我们不妨将其转化成一个图。将每一个人作为一个点(编号1…N),若两个人之间有一场相亲,则在对应的点之间连接一条无向边。(如下图)
img1.png
因为相亲总是在男女之间进行的,所以每一条边的两边对应的人总是不同性别。假设表示男性的节点染成白色,女性的节点染色黑色。对于得到的无向图来说,即每一条边的两端一定是一白一黑。如果存在一条边两端同为白色或者黑色,则表示这一条边所表示的记录有误。
由于我们并不知道每个人的性别,我们的问题就转化为判定是否存在一个合理的染色方案,使得我们所建立的无向图满足每一条边两端的顶点颜色都不相同。
那么,我们不妨将所有的点初始为未染色的状态。随机选择一个点,将其染成白色。再以它为起点,将所有相邻的点染成黑色。再以这些黑色的点为起点,将所有与其相邻未染色的点染成白色。不断重复直到整个图都染色完成。(如下图)
img2.png
在染色的过程中,我们应该怎样发现错误的记录呢?相信你一定发现了吧。对于一个已经染色的点,如果存在一个与它相邻的已染色点和它的颜色相同,那么就一定存在一条错误的记录。(如上图的4,5节点)
到此我们就得到了整个图的算法:
选取一个未染色的点u进行染色
遍历u的相邻节点v:若v未染色,则染色成与u不同的颜色,并对v重复第2步;若v已经染色,如果 u和v颜色相同,判定不可行退出遍历。
若所有节点均已染色,则判定可行。
接下来就动手写写吧!
输入
第1行:1个正整数T(1≤T≤10)
接下来T组数据,每组数据按照以下格式给出:
第1行:2个正整数N,M(1≤N≤10,000,1≤M≤40,000)
第2…M+1行:每行两个整数u,v表示u和v之间有一条边
输出
第1…T行:第i行表示第i组数据是否有误。如果是正确的数据输出”Correct”,否则输出”Wrong”
Sample Input
2
5 5
1 2
1 3
3 4
5 2
1 5
5 5
1 2
1 3
3 4
5 2
3 5
Sample Output
Wrong
Correct
#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 8 * 1e5 + 10;
int t, n, m;
int color[N];
vector <int >vec[N];
bool dfs(int now,int col)
{
color[now] = col;
for (int i = 0; i<vec[now].size(); i++)
{
int temp = vec[now][i];
if (color[now]==color[temp]) return false;
if (!color[temp]) {
//color[temp] = 2;这应该要调用dfs了
if (!dfs(temp, 3 - col))return false;
}
}
return true;
}
int main()
{
bool flag ;
int u,v;
cin >> t;
while (t--)
{
cin>>n>>m;
memset(color, 0, sizeof(color));
for (int i = 1; i <= n; i++) if (vec[i].size()) vec[i].clear();
while (m--)
{
cin>>u>>v;
vec[u].push_back(v);
vec[v].push_back(u);
}
flag = true;
for (int i = 1; i <= n; i++)
{
if (!color[i]) {
if (!dfs(i, 1)) {
flag = false;
break;
}
}
}
if (flag == true)cout << "Correct" << endl;
else cout << "Wrong" << endl;
}
return 0;
}
11、欧拉路(1)
描述
小Hi和小Ho最近在玩一个解密类的游戏,他们需要控制角色在一片原始丛林里面探险,收集道具,并找到最后的宝藏。现在他们控制的角色来到了一个很大的湖边。湖上有N个小岛(编号1…N),以及连接小岛的M座木桥。每座木桥上各有一个宝箱,里面似乎装着什么道具。
湖边还有一个船夫,船夫告诉主角。他可以载着主角到任意一个岛上,并且可以从任意一个岛上再载着主角回到湖边,但是主角只有一次来回的机会。同时船夫告诉主角,连接岛屿之间的木桥很脆弱,走过一次之后就会断掉。
因为不知道宝箱内有什么道具,小Hi和小Ho觉得如果能把所有的道具收集齐肯定是最好的,那么对于当前岛屿和木桥的情况,能否将所有道具收集齐呢?
举个例子,比如一个由6个小岛和8座桥组成的地图:
week49_1.png
主角可以先到达4号小岛,然后按照4->1->2->4->5->6->3->2->5的顺序到达5号小岛,然后船夫到5号小岛将主角接回湖边。这样主角就将所有桥上的道具都收集齐了。
输入
第1行:2个正整数,N,M。分别表示岛屿数量和木桥数量。1≤N≤10,000,1≤M≤50,000
第2…M+1行:每行2个整数,u,v。表示有一座木桥连接着编号为u和编号为v的岛屿,两个岛之间可能有多座桥。1≤u,v≤N
输出
第1行:1个字符串,如果能收集齐所有的道具输出“Full”,否则输出”Part”。
Sample Input
6 8
1 2
1 4
2 4
2 5
2 3
3 6
4 5
5 6
Sample Output
Full
#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <string.h>
#include <stdio.h>
using namespace std;
const int N = 8 * 1e5 + 10;
int n, m;
bool flag;
int du[N];
int main()
{
int u, v;
cin >> n >> m;
memset(du, 0, sizeof(du));
while (m--)
{
cin>>u>>v;
du[u]++;
du[v]++;
}
flag = false;
int sum = 0;
for (int i = 1; i <= n; i++)
{
if (du[i] % 2==1)sum++;
}
if (sum == 2 || sum == 0)flag = true;
if (flag == true)cout << "Full" << endl;
else cout << "Part" << endl;
return 0;
}