四、学算法啦啦啦——dp,并查集等 [Cloned] F - 最长公共子序列 以及最后十二个

原题:

A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, ..., xm > another sequence Z = < z1, z2, ..., zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, ..., ik > of indices of X such that for all j = 1,2,...,k, x ij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.

题意:

给出两个字符串,问顺序相同的字符有多少个,注意是顺序相同,不用管中间是否隔了多少个字符

题解:

求最长公共子序列的问题,数组dp[i][j]代表第一个数列从0到i和第二个数列从0到j有多少个公共子序列,然后状态方程表示为如果两个字符相等,那么dp[i][j]=dp[i-1][j-1]+1,如果不相等dp[i][j] = max(dp[i-1][j],dp[i][j-1]);这两个转移方程比较好写,就是大白话如果相同的字符就加一,如果不相同就取前边最大的。

代码:AC

using namespace std;
char s1[1000],s2[1000];
int dp[1000][1000];
int max(int x,int y)
{
	return x>y?x:y;
}
int main()
{
	int len1,len2;
	int i,j;
	while(cin>>s1>>s2)
	{
		len1 = strlen(s1);
		len2 = strlen(s2);
		for(i = 0;i <= len1; i++) 
			dp[i][0]=0; 
		for(i = 0;i <= len2; i++) 
			dp[0][i]=0;
		for(i = 1;i <=len1; i++)
		{
			for(j = 1;j <= len2; j++ )
			{
				if(s1[i-1]==s2[j-1]) 
					dp[i][j]=dp[i-1][j-1]+1;
				else 
					dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
			}
		}
	cout << dp[len1][len2]<<endl;
	}
return 0;
}

四、学算法啦啦啦——dp,并查集等 [Cloned]  H - 记忆化搜索  以及最后十一个题

原题:

Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个区域中最长底滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子

 1  2  3  4 5

16 17 18 19 6

15 24 25 20 7

14 23 22 21 8

13 12 11 10 9


一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。

题意:

题解:

(看的别人博客)

就是找递减最长序列,从一个点能走的最多的步数一定周四周某一个点的的最长步数加一,然后记忆化搜索一直找到最后一个点然后记录这个点的步数为1,之后不断退栈返回步数加一,就可以找出某个点的最多步数,一直到起点。

代码:

#include<iostream>
#include<cstring>
using namespace std;
int map[120][120];
int dp[120][120];
int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
int r,c;
int ski(int x,int y)
{
	if(dp[x][y]!=0)
		return dp[x][y];
	int maxn=0,t;
	for(t=0;t<4;t++)
	{
		int temx=x+dir[t][0],temy=y+dir[t][1];
		if(temx>=0&&temy>=0&&temx<r&&temy<c&&map[temx][temy]<map[x][y])
		{
			int s=ski(temx,temy);
			if(s>maxn)
				maxn=s;
		}
	}
	dp[x][y]=maxn+1;
	return maxn+1;
}

int main()
{
	cin>>r>>c;
	int i,j,mx=-1;
	for(i=0;i<r;i++)
		for(j=0;j<c;j++)
			cin>>map[i][j];
	memset(dp,0,sizeof(dp));
	for(i=0;i<r;i++)
	{
		for(j=0;j<c;j++)
		{
			dp[i][j]=ski(i,j);
			if(dp[i][j]>mx)
				mx=dp[i][j];
		}
	}
	cout<<mx<<endl;
	return 0;
}

四、学算法啦啦啦——dp,并查集等 [Cloned]  I - trie树

原题:

Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀). 

题意:

题解:

直接查询肯定会超时,所以要构建字典树,因要储存二十六个字母所以构建二十六个分支,然后输入单词构建字典树,然后再从查询字头。之前对字典树不太熟悉,看了几篇文章才慢慢写出来,理解了字典树的用法之后这个题就没什么困难了。

代码:AC

#include<iostream>
#include<cstring>
char str[20]; 
using namespace std;
struct node
{
	int counts;
	node *next[26];
	node()
	{
		counts=0;
		memset(next,0,sizeof(next));
	}
};
node *root=new node();
node *p;
void insert()
{
	p=root;
	int i;
	for(i=0;str[i]!='\0';i++)
	{
		int num=str[i]-'a';
		if(p->next[num]==NULL)
			p->next[num]=new node();
		p=p->next[num];
		p->counts++;
	}
}
int search()
{
	p=root;
	int i;
	for(i=0;str[i]!='\0';i++)
	{
		int num=str[i]-'a';
		if(p->next[num]==NULL)
			break;
		p=p->next[num];
	}
	if(str[i])
		return 0;
	return p->counts;
}
int main()
{
	while(gets(str),*str)
		insert();
	while(gets(str)!=NULL)
		cout<<search()<<endl;
	return 0;
}

 四、学算法啦啦啦——dp,并查集等 [Cloned]  J - trie树

 原题:

An encoding of a set of symbols is said to be immediately decodable if no code for one symbol is the prefix of a code for another symbol. We will assume for this problem that all codes are in binary, that no two codes within a set of codes are the same, that each code has at least one bit and no more than ten bits, and that each set has at least two codes and no more than eight. 

Examples: Assume an alphabet that has symbols {A, B, C, D} 

The following code is immediately decodable: 
A:01 B:10 C:0010 D:0000 

but this one is not: 
A:01 B:10 C:010 D:0000 (Note that A is a prefix of C) 

题意:

给出一系列编码,问是否会出现重复编码,即某些编码与另外编码的前部分重合。

题解:

因为数据结构学了哈夫曼编码,这个题写起来就比较假单,构建结构体包括左指针和右指针分别代表0和1,然后一个标志代表是否有编码停在这个节点,也就说如果之前有编码走这条路并且停下,之后再有编码走这条路就代表有重合,而且编码最后一个节点必须是重新申请的节点,如果是之前存在的节点就代表被别的编码覆盖。

代码:AC

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef struct node
{
	node *right;
	node *left;
	int log;
}node;
int flag,end=0;
char str[100];
void hafuman()
{		
	node *root,*p;
	root=(node*)malloc(sizeof(node));
	root->right=NULL;
	root->left=NULL;
	root->log=0;
	while(scanf("%s",str)!=EOF)
	{
		end=1;
		if(strcmp(str,"9")==0)
			break;
		p=root;
		int len=strlen(str);
		int i;
		for(i=0;i<len;i++)
		{	
			if(str[i]=='0')
			{
				if(p->left)
				{
					p=p->left;
					if(p->log==1)
						flag=1;
				}
				else
				{
					p->left=(node*)malloc(sizeof(node));
					p->left->left=NULL;
					p->left->right=NULL;
					p->left->log=0;
					p=p->left;
				}
			}
			else if(str[i]=='1')
			{
				if(p->right)
				{
					p=p->right;
					if(p->log==1)
						flag=1;
				}
				else
				{
					p->right=(node*)malloc(sizeof(node));
					p->right->left=NULL;
					p->right->right=NULL;
					p->right->log=0;
					p=p->right;
				}
			}

		}	
		p->log=1;
	}
}
				
		
int main()
{
	int i=1;
	while(i)
	{
		end=0;
		flag=0;
		hafuman();
		if(end==0)
			break;
		if(flag)
			cout<<"Set "<<i<<" is not immediately decodable"<<endl;
		else
			cout<<"Set "<<i<<" is immediately decodable"<<endl;
		i++;
	}
	return 0;
}	
	

 

四、学算法啦啦啦——dp,并查集等 [Cloned]  K - 并查集

原题:

Today is Ignatius' birthday. He invites a lot of friends. Now it's dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers. 

One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table. 

For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least. 

题意:

一个人过生日邀请很多朋友,只有相互认识的朋友才能坐在同一张桌子上,所谓相互认识包括直接认识和间接认识,问至少需要多少张桌子。

题解:

简单的并查集应用,之前对并查集也不是很熟悉,了解了一下感觉就是森林的合并,有相同根的节点就是一个集合,理解了之后就是很简单的输入输出问题了,不断输入不断合并,然后查找到最后有多少个根节点,也就是需要多多少张桌子。

代码:

 

#include<iostream>
#include<cstring>
using namespace std;
int flag[1020],node[1020];
int find(int x)
{
	if(x!=node[x])
		node[x]=find(node[x]);
	return node[x];
}
void merge(int x,int y)
{
	x=find(x);
	y=find(y);
	node[x]=y;
	
}
int main()
{
	int t;cin>>t;
	while(t--)
	{
		int n,m,a,b;
		cin>>n>>m;
		int i;
		for(i=1;i<=n;i++)
		{
			node[i]=i;
			flag[i]=0;
		}
		for(i=1;i<=m;i++)
		{
			cin>>a>>b;
			merge(a,b);
		}
		int sum=0;
		for(i=1;i<=n;i++)
			flag[find(i)]=1;
		for(i=1;i<=n;i++)
			if(flag[i])
				sum++;
		cout<<sum<<endl;
	}
	return 0;
}

四、学算法啦啦啦——dp,并查集等 [Cloned]  L - 并查集

原题:

Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others. 
In the Not-Spreading-Your-Sickness University (NSYSU), there are many student groups. Students in the same group intercommunicate with each other frequently, and a student may join several groups. To prevent the possible transmissions of SARS, the NSYSU collects the member lists of all student groups, and makes the following rule in their standard operation procedure (SOP). 
Once a member in a group is a suspect, all members in the group are suspects. 
However, they find that it is not easy to identify all the suspects when a student is recognized as a suspect. Your job is to write a program which finds all the suspects.

题意:

感染病毒的问题,只要是和感染嫌疑人在同一个组里,那么这个组所有人都成为感染嫌疑人,找出所有的感染嫌疑人。

题解:

依然是并查集的简单应用,感觉并查集这个好好用啊,从编号为0的人开始合并,只要是有可能感染的都并到一个集合里,然后输出有多少可能感染的人就ok了

代码:

#include<iostream>
#include<cstring>
using namespace std;
int flag[30010],node[30010];

int find(int x)
{
	if(node[x]==x)
		return x;
	return find(node[x]);
}

void merge(int x,int y)
{
	x=find(x);
	y=find(y);
	if(x==y)
		return;
	node[x]=y;
}

int main()
{
	int n,m;
	while(cin>>n>>m)
	{
		if(n+m==0)
			break;
		int i,j,num,s,t;
		for(i=0;i<=n;i++)
			node[i]=i;
		memset(flag,0,sizeof(flag));
		for(i=1;i<=m;i++)
		{
			cin>>num;
			cin>>s;
			for(j=1;j<num;j++)
			{
				cin>>t;
				merge(s,t);
				s=t;
			}
		}
		j=find(0);
		int ans=1;
		for(i=1;i<=n;i++)
		{
			if(j==find(i))
				ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
}

 四、学算法啦啦啦——dp,并查集等 [Cloned]  M - 并查集、

原题:

An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have set up a wireless network with the lap computers, but an unexpected aftershock attacked, all computers in the network were all broken. The computers are repaired one by one, and the network gradually began to work again. Because of the hardware restricts, each computer can only directly communicate with the computers that are not farther than d meters from it. But every computer can be regarded as the intermediary of the communication between two other computers, that is to say computer A and computer B can communicate if computer A and computer B can communicate directly or there is a computer C that can communicate with both A and B. 

In the process of repairing the network, workers can take two kinds of operations at every moment, repairing a computer, or testing if two computers can communicate. Your job is to answer all the testing operations. 

题意:

通讯修复问题,有n台电脑,他们最大的通讯距离是L,然后给出所有电脑的坐标,开始时所有电脑都是损坏的,然后输入操作修复某台电脑或者测试某两台电脑之间能否联络。

题解:

显然是还是并查集问题(废话啊题头写着呢),但是因为要处理一个距离的问题,所有输入的时候创建一个二维vector来储存某台电脑周围相聚小于L的所有电脑的序列,也就是说一旦修复了这台电脑,如果范围内有已经修复的电脑,那么就合并在一个集合里边。测试是否联络就是查询两台电脑是否在同一个集合里,也就是是否有相同的根,并查集真的好用啊,太简洁了。

代码:AC

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;

int x[1010],y[1010],node[1010];
vector<int> v[1010];
bool yes[1010];

int find(int x)
{
	if(x==node[x])
		return x;
	return find(node[x]);
}

void merge(int x,int y)
{
	x=find(x);
	y=find(y);
	if(x==y)
		return;
	node[x]=y;
}

int main()
{
	int n,d,i,j;
	cin>>n>>d;
	for(i=1;i<=n;i++)
	{
		cin>>x[i]>>y[i];
		node[i]=i;
	}
	for(i=1;i<=n;i++)
	{
		for(j=i+1;j<=n;j++)
		{
			if(((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]))<=d*d)
			{
				v[i].push_back(j);
				v[j].push_back(i);
			}
		}
	}
	memset(yes,false,sizeof(yes));
	char str[2];
	while(cin>>str)
	{		
		int a,b;
		if(str[0]=='O')
		{
			cin>>a;
			yes[a]=true;
			for(i=0;i<v[a].size();i++)
			{
				if(yes[v[a][i]])
				{
					merge(a,v[a][i]);
				}
			}
		}
		else
		{
			cin>>a>>b;
			a=find(a);
			b=find(b);
			if(a==b)
				cout<<"SUCCESS"<<endl;
			else
				cout<<"FAIL"<<endl;
		}
	}
	return 0;
}

 

四、学算法啦啦啦——dp,并查集等 [Cloned]  N - 并查集

原题:

There are so many different religions in the world today that it is difficult to keep track of them all. You are interested in finding out how many different religions students in your university believe in. 

You know that there are n students in your university (0 < n <= 50000). It is infeasible for you to ask every student their religious beliefs. Furthermore, many students are not comfortable expressing their beliefs. One way to avoid these problems is to ask m (0 <= m <= n(n-1)/2) pairs of students and ask them whether they believe in the same religion (e.g. they may know if they both attend the same church). From this data, you may not know what each person believes in, but you can get an idea of the upper bound of how many different religions can be possibly represented on campus. You may assume that each student subscribes to at most one religion.

题意:

统计宗教的数目,因为不能直接去询问同学,所以只能从相同的集合入手,参加过相同聚会的同学为同一个宗教。

题解:

依然是简单的并查集运算,把每一个聚会中所有人并到同一个集合中去,最后查询有多少个根节点就是有多少个宗教。

代码:AC

#include<iostream>
#include<cstring>
using namespace std;
int node[50010];

int find(int x)
{
	if(x==node[x])
		return x;
	return find(node[x]);
}

void merge(int x,int y)
{
	x=find(x);
	y=find(y);
	if(x==y)
		return ;
	node[x]=y;
}

int main()
{
	int n,m,j=0;
	while(cin>>n>>m)
	{
		if(n+m==0)
			break;
		j++;
		int i;
		for(i=1;i<=n;i++)
			node[i]=i;
		int a,b;
		for(i=0;i<m;i++)
		{
			cin>>a>>b;
			merge(a,b);
		}
		int sum=0;
		for(i=1;i<=n;i++)
		{
			if(node[i]==i)
			{
				sum++;
			}
		}
		cout<<"Case "<<j<<": "<<sum<<endl;
	}
	return 0;
}

四、学算法啦啦啦——dp,并查集等 [Cloned]  P - Play on Words】

原题:

Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to solve it to open that doors. Because there is no other way to open the doors, the puzzle is very important for us. 

There is a large number of magnetic plates on every door. Every plate has one word written on it. The plates must be arranged into a sequence in such a way that every word begins with the same letter as the previous word ends. For example, the word ``acm'' can be followed by the word ``motorola''. Your task is to write a computer program that will read the list of words and determine whether it is possible to arrange all of the plates in a sequence (according to the given rule) and consequently to open the door. 

题意:

词语接龙问题,给出一些单词,一个单词第第一个字母和上一个单词的最后一个字母相同那么就可以接上,问给出的所有单词能否组成完成的接龙。

题解:

统计每个单词的第一个字母作为入度,统计每个单词的最后一个字母作为出度,有以下两种情况可以组成完整的词语接龙,

一是,入度和出度只有两个字母不同,而且这两个字母的出入度都是相差一,这样可以组成完整的一条链

二是,所有字母的入度和出度都相同,说明可以组成一个环,同样可以完成接龙。

代码:AC

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int in[30],out[30],visit[30];
int node[30];
int find(int x)
{
	if(x==node[x])
		return x;
	return find(node[x]);
}
void merge(int x,int y)
{
	x=find(x);
	y=find(y);
	if(x==y)
		return ;
	node[x]=y;
}

int main()
{
	int t,a,b;
	cin>>t;
	char str[1100];
	while(t--)
	{
		int n,i,j=0;
		cin>>n;
		memset(out,0,sizeof(out));
		memset(in,0,sizeof(in));
		memset(visit,0,sizeof(visit));
		for(i=0;i<26;i++)
			node[i]=i;
		while(n--)
		{
			cin>>str;
			a=str[0]-'a';
			b=str[strlen(str)-1]-'a';
			in[a]++;
			out[b]++;
			merge(a,b);
			visit[a]=1;
			visit[b]=1;
		}
		int root=0;
		for(i=0;i<26;i++)
		{
			if(node[i]==i&&visit[i]==1)
				root++;
		}
		if(root!=1)
		{
			cout<<"The door cannot be opened."<<endl;
			continue;
		}
		int p[30];
		for(i=0;i<26;i++)
		{
			if(visit[i]&&out[i]!=in[i])
				p[j++]=i;
		}
		if((j==0)||(j==2&&abs(out[p[0]]-in[p[0]])==1&&abs(out[p[1]]-in[p[1]])==1))
		{
			cout<<"Ordering is possible."<<endl;
			continue;
		}
		cout<<"The door cannot be opened."<<endl;
	}
	return 0;
}
	

 四、学算法啦啦啦——dp,并查集等 [Cloned]   S - 二分或者hash

原题:

The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .

题意:

有四个数组,从每个数组中取一个数,让他们的加和为0,问一共有多少种不同的组合方式。

题解:

题头好像要让用二分,看了一篇别人的博客发现了一种更好的办法,先把各个序列排序,然后把a,b两个数列的所有加和可能算出来,一共有n**2种,然后直接用upper_bound和lower_bound函数直接在这些加和中找c+d的相反数,相当的暴力,然而可以过。

代码:AC                                                                                                                                            

#include<iostream>
#include<cstdio> 
#include<algorithm> 
using namespace std; 
int ans,n,p=0; 
int a[4005],b[4005]; 
int c[4005],d[4005]; 
int o[4005*4005]; 
int main() 
{ 
		int i,j;
		cin>>n;
        for(i=1;i<=n;i++) 
			cin>>a[i]>>b[i]>>c[i]>>d[i];
        for(i=1;i<=n;i++) 
            for(j=1;j<=n;j++) 
			{
                o[++p]=a[i]+b[j]; 
			}
        sort(o+1,o+p+1); 
        for(i=1;i<=n;i++)
		{			
            for(j=1;j<=n;j++) 
			{
                ans+=upper_bound(o+1,o+p+1,-c[i]-d[j])-lower_bound(o+1,o+p+1,-c[i]-d[j]); 
			}
		}
        printf("%d\n",ans); 
		return 0;
} 	

五、学算法啦啦啦——搜索、线段树基础、图论基础 [Cloned]  G - 拓扑排序

原题;

The system of Martians' blood relations is confusing enough. Actually, Martians bud when they want and where they want. They gather together in different groups, so that a Martian can have one parent as well as ten. Nobody will be surprised by a hundred of children. Martians have got used to this and their style of life seems to them natural. 
And in the Planetary Council the confusing genealogical system leads to some embarrassment. There meet the worthiest of Martians, and therefore in order to offend nobody in all of the discussions it is used first to give the floor to the old Martians, than to the younger ones and only than to the most young childless assessors. However, the maintenance of this order really is not a trivial task. Not always Martian knows all of his parents (and there's nothing to tell about his grandparents!). But if by a mistake first speak a grandson and only than his young appearing great-grandfather, this is a real scandal. 
Your task is to write a program, which would define once and for all, an order that would guarantee that every member of the Council takes the floor earlier than each of his descendants.

题意:

火星人的父子关系问题,一个人可能有多个父亲(并没关系吗??哪怕是火星人),然后给出每个人有哪些孩子,找出一种排序方式能够保证每个火星人都在他们的孩子之前。

题解:

简单的拓扑排序问题,数据结构没白学,创建二维数组来表示父子关系,直到找到入度为0的序号就输出,然后将这个序号所对应的所有出度变为0,然后再去寻找入度为0的序号,如此反复直到找完所有的

代码:AC

#include<iostream>
#include<cstring>
using namespace std;
#define Num 101
int N;
int map[Num][Num];
int num[Num];
 
void find()
{
    int i=1,j;
    for(i=1;i<=N;i++)
        if(num[i] == 0)
            break;
    num[i] = -1;
	cout<<i<<" ";
    for(j=1;j<=N;j++)
        if(map[i][j] == 1)
            num[j]--;
}
int main()
{
	cin>>N;
	int i;
    for(i = 1;i <= N;i++)
    {
        int tmp;
		cin>>tmp;
        while(tmp != 0)
        {
            map[i][tmp] = 1;
            num[tmp]++;
			cin>>tmp;
        }
    }
    
    for(i = 1;i <= N;i++)
        find();
    return 0;
}

 五、学算法啦啦啦——搜索、线段树基础、图论基础 [Cloned]   H - 拓扑排序

原题:

有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。

题意:

题解:

依然是简单的拓扑排序,不断找入度为0的点然后将他的的所有出度都消除掉,还要保证字典序顺序输出

#include <iostream>
#include <string.h>
using namespace std;
int map1[505][505];
int ind[505],flag[505];
void tuopsort(int n)
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
    {
        if(map1[i][j]!=0)
            ind[j]++;
    }
    for(int i=1; i<=n; i++)
    {
        int k=1;
        while(ind[k]!=0)
            k++;
        flag[i]=k;
        ind[k]=-1;
        for(int j=1; j<=n; j++)
        {
            if(map1[k][j]!=0)
                ind[j]--;
        }
    }
}
int main()
{
    int p1,p2,n,m;
    while(cin>>n>>m)
    {
        memset(ind,0,sizeof(ind));
        memset(map1,0,sizeof(map1));
        memset(flag,0,sizeof(flag));
        for(int i=0; i<m; i++)
        {
            cin>>p1>>p2;
            map1[p1][p2]=1;
          ///  ind[p2]++;
        }
        tuopsort(n);
        cout<<flag[1];
        for(int i=2; i<=n; i++)
            cout<<" "<<flag[i];
        cout<<endl;
    }
    return 0;
}

五、学算法啦啦啦——搜索、线段树基础、图论基础 [Cloned】  N - 最短路

原题:

Stockbrokers are known to overreact to rumours. You have been contracted to develop a method of spreading disinformation amongst the stockbrokers to give your employer the tactical edge in the stock market. For maximum effect, you have to spread the rumours in the fastest possible way. 

Unfortunately for you, stockbrokers only trust information coming from their "Trusted sources" This means you have to take into account the structure of their contacts when starting a rumour. It takes a certain amount of time for a specific stockbroker to pass the rumour on to each of his colleagues. Your task will be to write a program that tells you which stockbroker to choose as your starting point for the rumour, as well as the time it will take for the rumour to spread throughout the stockbroker community. This duration is measured as the time needed for the last person to receive the information.

题意:

股票经济人当中传播谣言,每个经济人只相信特定的某些经济人,而且每个经济人传播到其他人需要的时间不同,也就是带权路径,问谣言传遍所有经济人所需要的最短时间,要注意并不知道从哪一个经济人开始传播。

题解:

显然是有向图图找最短路径问题,因为要不确定起点,所以要使用floyd算法找出所有的点到其他点的最短路径,因为folyd算法找出的是的到其他点的最短路径,所以对于每一个起点,再寻找需要的最长时间,然后对于所有的最长事件找出其中的最短时间,这就是不确定起点的最短路径的答案。

代码:AC

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
int gragh[110][110];
void floyd()
{
	int i,j,k;
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
			gragh[i][j]=100000;
		gragh[i][i]=0;
	}
	for(i=1;i<=n;i++)
	{
		int t;
		cin>>t;
		int a,w;
		while(t--)
		{
			cin>>a>>w;
			gragh[i][a]=w;
		}
	}
	for(k=1;k<=n;k++)
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
				if(i!=j&&gragh[i][j]>gragh[i][k]+gragh[k][j])
					gragh[i][j]=gragh[i][k]+gragh[k][j];
	int maxlen,minlen=100000,pos;
	for(i=1;i<=n;i++)
	{
		maxlen=0;
		for(j=1;j<=n;j++)
			if(i!=j&&maxlen<gragh[i][j])
				maxlen=gragh[i][j];
		if(minlen>maxlen)
		{
			minlen=maxlen;
			pos=i;
		}
	}
	if(minlen<100000)
		cout<<pos<<' '<<minlen<<endl;
	else
		cout<<"disjoint"<<endl;
	return;
}
		
int main()
{
	while(cin>>n&&n)
		floyd();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值