2016/6/1 第九届ACM大赛前夕模板总结



一、最小生成树...............................................................................................................2

1、最小生成树:v
+ v + value布线问题.................................................................2

3、prim算法之矩阵类型.........................................................................................4

4、输出最小生成树个边权值累加和(矩阵类型).....................................................5

5、求出最小生成树中边的最大值(矩阵类型)........................................................6

6、prim算法变形之引水工程(矩阵型)完全矩阵...................................................8

7、Kruskal(克鲁斯卡尔)(不是完全边,v+v+value)..........................................9

8、还差多少对v+v才能达到最小生成树................................................................11

9、先判断是否畅通,再用最小生成树求最小花费..................................................12

10、dfs欧拉回路.................................................................................................15

12、次小生成树(v+v+value型最小花费方案个数).............................................16

13、判断最小生成树是否唯一................................................................................19

13、最优比率生成树
(最优比例生成树)................................................................21

14、判断边与一个图最小生成shu的关系.............................................................23

15、hdu
3371 最小生成树(有重边)................................................................25

二、二分图....................................................................................................................26

1、两列相同数的最大匹配数(月老的难题).........................................................26

三、树状数组+线段树组................................................................................................27

1、士兵杀敌<1>(树状数组模板)........................................................................28

2、士兵杀敌<2>(树状数组模板)......................................................................29

3、士兵杀敌(三)(rmq求区间最大最小值之差)..............................................30

4、第i个人的军功数.............................................................................................31

四、数组A[1..n]中超过半数的元素都相同时,该数组被称为含有主元素。...................32

五、
快排.....................................................................................................................33

1、数组排序..........................................................................................................33

2、快速排序一般版本(可求第K大元素)............................................................33

3、归并排序求逆序数............................................................................................34

4、求第k大的数.................................................................................................35

5、RMQ模板
,返回区间最值 、 最值的下标...................................................36

6、快速幂求余模板................................................................................................37

7、最长公共子序列..............................................................................................37

七、二分.......................................................................................................................39

八、最短路径................................................................................................................39

1、最短路径+畅通工程续.......................................................................................39

2、畅通工程再续...................................................................................................41

3、公交车最短路径(公交站是英文名字).............................................................42

22、最短路径 求最短距离..........................................................................................44

4、单源最短路Dijkstra算法。只不过起点给你多个,然后求可以到达的目的地中路径最短的一条   45

5、飘谊想知道他走完观光道路并回到源点的最短路径...........................................47

6、给多个坐标,求最短路径的最大边....................................................................48

7、最k短路..........................................................................................................50

8、一棵树上的任意两点的距离..............................................................................52

9、最短路径spfa..................................................................................................54

10、aij矩阵类型的单源最短路径并且输出最短权值和最短路径.............................56

11、邻接矩阵的单源最短路径................................................................................58

九、最大流....................................................................................................................61

1、简单最大流.......................................................................................................61

2、现在要求从1点到n点在从n点返回1点的最短路..........................................63

十二、贪心问题.............................................................................................................65

4、拦截导弹..........................................................................................................65

5、最少拦截系统...................................................................................................66

5、心急的c小佳....................................................................................................66

7、radar...............................................................................................................68

十三、几何问题.............................................................................................................69

1、点线距离..........................................................................................................69

2、是否是凸多边形................................................................................................69

3、点是否在凸多边形内或边上..............................................................................69

4、点在任意多边形内或边上..................................................................................69

十四、
kmp算法.........................................................................................................70

1、最小的匹配位置................................................................................................70

2、子串出现的次数................................................................................................71

3、简单求周期......................................................................................................72

4、求最长的公共子串,要注意的是字典序最小......................................................73

5、kmp算法模板(子串个数).............................................................................74

6、求S中最长回文串的长度.................................................................................75

7、容斥定理..........................................................................................................76

8、字典树的简单应用............................................................................................78

8、括号匹配.........................................................................................................79

9、求一个字符串的最长递增子序列的长度.............................................................81

一、最小生成树

1、最小生成树:v
+ v + value布线问题

布线问题:由于安全问题,只能选择一个楼连接到外界供电设备。

/*

1

v e

4 6(4个顶点,正好六个边)

1 2 10

2 3 10

3 1 10

1 4 1

2 4 1

3 4 1

1 3 5 6(连接到外界供电设备所需要的费用)

*/

#include<iostream>

using namespace std;

#define MAX 505

#define MAXCOST 0x7fffffff

int graph[MAX][MAX];

int prim(int graph[][MAX], int n)

{

int lowcost[MAX];

int mst[MAX];

int i, j, min, minid, sum =0;

for (i = 2; i <= n; i++)

{

lowcost[i] = graph[1][i];

mst[i] = 1;

}

mst[1] = 0;

for (i = 2; i <= n; i++)

{

min = MAXCOST;

minid = 0;

for (j = 2; j <= n;j++)

{

if (lowcost[j]< min && lowcost[j] != 0)

{

min =lowcost[j];

minid =j;

}

}

//cout <<"V" << mst[minid] << "-V" << minid<< "=" << min << endl;

sum += min;

lowcost[minid] = 0;

for (j = 2; j <= n;j++)

{

if(graph[minid][j] < lowcost[j])

{

lowcost[j]= graph[minid][j];

mst[j] =minid;

}

}

}

return sum;

}

int main()

{

int i, j, k, m, n;

int x, y, cost;

int zushu;

cin>>zushu;

while(zushu--)

{

cin >> m >> n;//m=顶点的个数,n=边的个数

for (i = 1; i <= m;i++)

{

for (j = 1; j<= m; j++)

{

graph[i][j]= MAXCOST;

}

}

for (k = 1; k <= n;k++)

{

cin >> i>> j >> cost;

graph[i][j] =cost;

graph[j][i] =cost;

}

cost = prim(graph, m);

int min_v=MAXCOST;

for(inti=1;i<=m;++i)

{

int t;

cin>>t;

if(t<min_v)

min_v=t;

}

cout <<cost+min_v<< endl;

}

return 0;

}

3、prim算法之矩阵类型

/*

1(组数)

3(3*3的矩阵)

0 990 692

990 0 179

692 179 0

//一个有n个顶点的无向图最多几条边
n(n-1)/2

//具有n个顶点的无向图,至少应有多少n-1条边才能确保是一个连通图

*/

#include "stdio.h"

#include "string.h"

#define N 500

#define INT 10000

bool vis[N];

int dis[N];

int a[N][N];

int main(){

int t;

scanf("%d",&t);

while(t--){

int n;

scanf("%d",&n);

int i,j,temp,k;

memset(vis,0,sizeof(vis));

for(i=1;i<=n;++i){

for(j=1;j<=n;++j){

scanf("%d",&a[i][j]);

}

}

for(i=1;i<=n;++i){

dis[i]=INT;

}

dis[1]=0;

for(i=1;i<=n;++i){

temp=INT;

k=0;

for(j=1;j<=n;++j){

if(!vis[j]&&dis[j]<temp){

temp=dis[j];

k=j;

}

}

vis[k]=1;

for(j=1;j<=n;++j){

if(!vis[j]&&dis[j]>a[k][j]){

dis[j]=a[k][j];

}

}

}

int max=0;

for(i=1;i<=n;++i){

if(max<dis[i])

max=dis[i];

}

printf("%d\n",max);

}

return 0;

}

4、输出最小生成树个边权值累加和(矩阵类型)

4

0 4 9 21

4 0 8 17

9 8 0 16

21 17 16 0

#include <stdio.h>

#include <string.h>

#define MaxInt 0x3f3f3f3f

#define N 110

int map[N][N],low[N],visited[N];

int n;

int prim()

{

int i,j,pos,min,result=0;

memset(visited,0,sizeof(visited));

visited[1]=1;pos=1;

for(i=1;i<=n;i++)

if(i!=pos)low[i]=map[pos][i];

for(i=1;i<n;i++)

{

min=MaxInt;

for(j=1;j<=n;j++)

if(visited[j]==0&&min>low[j])

{

min=low[j];pos=j;

}

result+=min;

visited[pos]=1;

//更新权值

for(j=1;j<=n;j++)

if(visited[j]==0&&low[j]>map[pos][j])

low[j]=map[pos][j];

}

return result;

}

int main()

{

int i,v,j,ans;

while(scanf("%d",&n)!=EOF)

{

memset(map,MaxInt,sizeof(map));

for(i=1;i<=n;i++)

for(j=1;j<=n;j++)

{

scanf("%d",&v);

map[i][j]=map[i][j]=v;

}

ans=prim();

printf("%d\n",ans);

}

return 0;

}

5、求出最小生成树中边的最大值(矩阵类型)

1

3

0 990 692

990 0 179

692 179 0

692

#include<stdio.h>

#define MAX 505

#define inf 999999

int c[MAX][MAX];

int n;

void prim()

{

int lowcost[MAX ];

int closest[MAX ];

bool s[MAX ];

s[1]=true;

for(int i=2;i<=n;i++)

{

lowcost[i]=c[1][i];

closest[i]=1;

s[i]=false;

}

for(int i=1;i<=n;i++)

{

int min=inf;

int j=i;

for(int k=2;k<=n;k++)

if((lowcost[k]<min)&&(!s[k]))

{

min=lowcost[k];

j=k;

}

//cout<<j<<" "<<closet[j]<<endl;输出最小生成树的路径。

s[j]=true;

for(int k=2;k<=n;k++)

{

if((c[j][k]<lowcost[k])&&(!s[k]))

{

lowcost[k]=c[j][k];

closest[k]=j;

}

}

}

//最小生成树的边值已经放大lowcost数组中了。遍历一下就可以得到最大最小值。

int result=-1;

for(int i=2;i<=n;i++)

{

if(result<lowcost[i])

result=lowcost[i];

}

printf("%d\n",result);

}

int main()

{

int t;

scanf("%d",&t);

while(t--)

{

scanf("%d",&n);

for(int i=1;i<=n;i++)

{

for(int j=1;j<=n;j++)

{

scanf("%d",&c[i][j]);

}

}

prim();

}

return 0;

}

6、prim算法变形之引水工程(矩阵型)完全矩阵

/*1

5

0 5 4 4 3 6

5 0 2 2 2 2

420
3 3 3

423
0 4 5

323
4 0 1

523
5 1 0*/

#include <stdio.h>

#include <string.h>

#define MaxInt 0x3f3f3f3f

#define N 303

int map[N][N],low[N],visited[N];

int n;

int prim()

{

int i,j,pos,min,result=0;

memset(visited,0,sizeof(visited));

visited[1]=1;pos=1;

for(i=1;i<=n;i++)

if(i!=pos)low[i]=map[pos][i];

for(i=1;i<n;i++)

{

min=MaxInt;

for(j=1;j<=n;j++)

if(visited[j]==0&&min>low[j])

{

min=low[j];

pos=j;

}

result+=min;

visited[pos]=1;

for(j=1;j<=n;j++)

if(visited[j]==0&&low[j]>map[pos][j])

low[j]=map[pos][j];

}

return result;

}

int main()

{

int i,v,j,ans,zushu;

scanf("%d",&zushu);

int a[303];

while(zushu--)

{

scanf("%d",&n);

memset(map,MaxInt,sizeof(map));

map[1][1]=0;

for(i=2;i<=n+1;++i)

{

scanf("%d",&map[i][1]);

map[1][i]=map[i][1];

}

getchar();

for(i=2;i<=n+1;i++)

for(j=2;j<=n+1;j++)

{

scanf("%d",&v);

map[i][j]=map[i][j]=v;

}

n=n+1;

ans=prim();

printf("%d\n",ans);

}

return 0;

}

7、Kruskal(克鲁斯卡尔)(不是完全边,v+v+value)

/*

但不一定有直接的公路相连,只要能间接通过公路可达即可

村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。

对每个测试用例,在1行里输出全省畅通需要的最低成本。

若统计数据不足以保证畅通,则输出“?”。

Sample Input

3 3

1 2 1

1 3 2

2 3 4

1(e) 3(v)

2 3 2

0 100

Sample Output

3

?

*/

#include<iostream>

#include<cstring>

#include<string>

#include<cstdio>

#include<algorithm>

using namespace std;

#define MAX 100

int father[MAX], son[MAX];

int v, l;

typedef struct Kruskal //存储边的信息

{

int a;

int b;

int value;

};

bool cmp(const Kruskal & a, const Kruskal & b)

{

return a.value < b.value;

}

int unionsearch(int x) //查找根结点+路径压缩

{

return x == father[x] ? x :unionsearch(father[x]);

}

bool join(int x, int y) //合并

{

int root1, root2;

root1 = unionsearch(x);

root2 = unionsearch(y);

if(root1 == root2) //为环

return false;

else if(son[root1] >=son[root2])

{

father[root2] =root1;

son[root1] +=son[root2];

}

else

{

father[root1] =root2;

son[root2] +=son[root1];

}

return true;

}

int main()

{

int ltotal, sum, flag;

Kruskal edge[MAX];

//scanf("%d",&ncase);

while(scanf("%d%d",&l, &v),l)

{

ltotal = 0, sum = 0,flag = 0;

for(int i = 1; i <=v; ++i) //初始化

{

father[i] = i;

son[i] = 1;

}

for(int i = 1; i <=l ; ++i)

{

scanf("%d%d%d",&edge[i].a, &edge[i].b, &edge[i].value);

}

sort(edge + 1, edge +1 + l, cmp); //按权值由小到大排序

int count=0;

for(int i = 1; i <=l; ++i)

{

if(join(edge[i].a,edge[i].b))

{

ltotal++;//边数加1

sum +=edge[i].value; //记录权值之和

//cout<<edge[i].a<<"->"<<edge[i].b<<endl;

}

if(ltotal == v- 1) //最小生成树条件:边数=顶点数-1

{

flag =1;

break;

}

count++;

}

//printf("count%d\n", count);

if(flag)

printf("%d\n",sum);

else

printf("?\n");

}

return 0;

}

8、还差多少对v+v才能达到最小生成树

/*

目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,

只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

v e

4 2

1 3

4 3

3 3

1 2

1 3

2 3

5 2

1 2

3 5

999 0

0

输出最少还需要建设的道路数目。

*/

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<algorithm>

using namespace std;

int pre[1010];

int unionsearch(int root) //查找父节点+路径压缩(非递归)

{

int son, tmp;

son = root;

while(root != pre[root])

root = pre[root];

while(son != root)

{

tmp = pre[son];

pre[son] = root;

son = tmp;

}

return root;

}

/*int unionsearch(int root) //查找父节点+路径压缩(递归)

{

return root == pre[root] ?root : unionsearch(pre[root]);

}*/

int main()

{

int num, road, total, i, start,end, root1, root2;

while(scanf("%d%d",&num, &road) && num)

{

total = num - 1;

for(i = 1; i <= num;++i)

pre[i] = i;

while(road--)

{

scanf("%d%d",&start, &end);

root1 =unionsearch(start);

root2 =unionsearch(end);

if(root1 != root2)

{

pre[root1] = root2;

total--;

}

}

printf("%d\n",total);

}

return 0;

}

9、先判断是否畅通,再用最小生成树求最小花费

/*

对每个测试用例,在 1行里输出全省畅通需要的最低成本。

若统计数据不足以保证畅通,则输出 No solution。

2

e v

3 3

1 2 1

1 3 2

2 3 4

1 3

2 3 2

样例输出

3

No solution

*/

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<algorithm>

using namespace std;

//判断是否畅通

int pre[1010];

int unionsearch(int root) //查找父节点+路径压缩(非递归)

{

int son, tmp;

son = root;

while(root != pre[root])

root = pre[root];

while(son != root)

{

tmp = pre[son];

pre[son] = root;

son = tmp;

}

return root;

}

//最小生成树

#define MAX 505

#define MAXCOST 0x7fffffff

int graph[MAX][MAX];

int prim(int graph[][MAX], int n)

{

int lowcost[MAX];

int mst[MAX];

int i, j, min, minid, sum =0;

for (i = 2; i <= n; i++)

{

lowcost[i] =graph[1][i];

mst[i] = 1;

}

mst[1] = 0;

for (i = 2; i <= n; i++)

{

min = MAXCOST;

minid = 0;

for (j = 2; j <= n;j++)

{

if (lowcost[j]< min && lowcost[j] != 0)

{

min =lowcost[j];

minid =j;

}

}

//cout <<"V" << mst[minid] << "-V" << minid<< "=" << min << endl;

sum += min;

lowcost[minid] = 0;

for (j = 2; j <= n;j++)

{

if(graph[minid][j] < lowcost[j])

{

lowcost[j]= graph[minid][j];

mst[j] =minid;

}

}

}

return sum;

}

int main()

{

int num, road, total, start,end, root1, root2;

int i, j, k, m, n;

int x, y, cost;

int zushu;

cin>>zushu;

while(zushu--)

{

cin >> n >> m ;//m=顶点的个数,n=边的个数

num=m,road=n;

for (i = 1; i <= m;i++)

{

for (j = 1; j<= m; j++)

{

graph[i][j]= MAXCOST;

}

}

//------------判断是否畅通

//num顶点,road道路

total = num - 1;

for(i = 1; i <= num;++i)

pre[i] = i;

for (k = 1; k <= n;k++)

{

cin >> i>> j >> cost;

graph[i][j] =cost;

graph[j][i] =cost;

start=i;

end=j;

root1 =unionsearch(start);

root2 =unionsearch(end);

if(root1 != root2)

{

pre[root1] = root2;

total--;

}

}

//cout<<total<<endl;

if(total<1)

{

cost = prim(graph, m);

printf("%d\n",cost);

}

else{

printf("No solution\n");

}

}

return 0;

}

10、dfs欧拉回路

/*

2

v e

4 3

1 2

1 3

1 4

一笔画就yes,不一笔画no

*/

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <vector>

#include <climits>

#include <algorithm>

#include <cmath>

#define LL long long

using namespace std;

vector<int>e[1010];

int deg[1010];

bool vis[1010];

void dfs(int u) {

vis[u] =
true;

for(int i = 0; i <e[u].size(); i++) {

if(!vis[e[u][i]]) {

dfs(e[u][i]);

}

}

}

int main() {

int kase,p,q,i,u,v,temp;

bool flag;

scanf("%d",&kase);

while(kase--) {

scanf("%d%d",&p,&q);

memset(deg,0,sizeof(deg));

memset(vis,false,sizeof(vis));

for(i = 0; i < 1010;i++)

e[i].clear();

for(i = 0; i < q; i++) {

scanf("%d%d",&u,&v);

e[u].push_back(v);

e[v].push_back(u);

deg[u]++;

deg[v]++;

}

dfs(1);

flag = true;

for(i = 1; i <= p; i++)

if(!vis[i]) {

flag = false;

break;

}

if(flag) {

for(temp = 0,i = 1; i<= p; i++) {

if(deg[i]&1) {

temp++;

if(temp > 2)break;

}

}

}

if(!flag || temp > 2)puts("No");

else puts("Yes");

}

return 0;

}

12、次小生成树(v+v+value型最小花费方案个数)

/*N个不同的城市里,这些城市分别编号1~N。

如果存在两种以上的最小花费方案则输出Yes,如果最小花费的方案只有一种,则输出No)

样例输入

2(组数)

3(v)
3(e)

v+v+value

1 2 1

2 3 2

3 1 3

4 4

1 2 2

2 3 2

3 4 2

4 1 2

样例输出

No

Yes

*/

#include<iostream>

#include<stdio.h>

#include<string>

#include<cstring>

#include<algorithm>

using namespace std;

#define MaxV 510

#define MaxE 200005

struct Edge

{

int x,y,dis;

};

Edge edge[MaxE],edge1[MaxE];       //分别是边数组
最小生成树中的边数组

int father[MaxV],Num[MaxV],num,dex,dey;        //并查集
num统计生成树边的条数 dex dey指枚举删除边的x,y坐标

void Init(int V)        //并查集初始化,单个元素自成集合

{

for(int i=1;i<=V;i++)

{

father[i]=i;

Num[i]=1;

}

}

int findfather(int x)     //寻找父结点,可以压缩路径。。

{

for(x;x!=father[x];x=father[x]) ;

return father[x];

}

void Union(int x,int y)

{

int t1,t2;

t1=findfather(x);

t2=findfather(y);

if(Num[t1]>Num[t2])

{

father[t2]=t1;

Num[t1]+=Num[t2];

}

else

{

father[t1]=t2;

Num[t2]+=Num[t1];

}

}

int comp(const void* p1,const void* p2)

{

return(*(Edge*)p1).dis>(*(Edge*)p2).dis;

}

int Krusual(int V,int E)

{

int sum=0;

for(int i=1;i<=E;i++)

{

if(findfather(edge[i].x)!=findfather(edge[i].y))

{

sum+=edge[i].dis;

Union(edge[i].x,edge[i].y);

edge1[++num]=edge[i];

}

}

return sum;

}

int AKrusual(int V,int E)

{

Init(V);

int sum=0;

qsort(edge+1,E,sizeof(edge[1]),comp);

int k;

for(k=1;k<=E;++k)

{

if(findfather(edge[k].x)!=findfather(edge[k].y))

{

if(edge[k].x==dex&&edge[k].y==dey)

{continue;}

if(edge[k].x==dey&&edge[k].x==dex)

{continue;}

sum+=edge[k].dis;

Union(edge[k].x,edge[k].y);

}

}

return sum;

}

bool Judge(int V)     //判断图是否连通,不连通则无法构造最小生成树

{

for(int m=1;m<=V-1;++m)

if(findfather(m)!=findfather(m+1))

return false;

return true;

}

int main()

{

int test,j,V,E;

scanf("%d",&test);

while(test--)

{

scanf("%d%d",&V,&E);

num=0;

for(j=1;j<=E;++j)

{

scanf("%d%d%d",&edge[j].x,&edge[j].y,&edge[j].dis);

}

qsort(edge+1,E,sizeof(edge[1]),comp);

Init(V);

int sum=Krusual(V,E);

int M=1000,temp;

for(int q=1;q<=num;++q)

{

dex=edge1[q].x;

dey=edge1[q].y;

temp=AKrusual(V,E);

if(temp<M&&Judge(V))

M=temp;

if(M==sum) break;

}

if(M==sum)printf("Yes\n");

else printf("No\n");

}

}

/*

13、判断最小生成树是否唯一

构成原最小生成树的边,一条边一条边的删。

*/

#include"stdio.h"

#include"stdlib.h"

struct A

{

int a,b;

int flag;

int len;

}eage[5555];

int n,m;

int set[111];

int cmp(const void *a,const void *b)

{

struct A *c,*d;

c=(struct A *)a;

d=(struct A *)b;

return c->len-d->len;

}

void build(int num)

{

int i;

for(i=1;i<=num;i++)  set[i]=i;

}

int find(int k)

{

if(set[k]==k) return
k;

set[k]=find(set[k]);

return set[k];

}

void Union(int f1,int f2)

{

set[f1]=f2;

}

int Kruskal(int t_d)

{

int i;

int ans;

int f1,f2;

int count=1;

ans=0;

for(i=0;i<m;i++)

{

if(count==n)break;

if(i==t_d)      continue;

f1=find(eage[i].a);

f2=find(eage[i].b);

if(f1==f2)     continue;

Union(f1,f2);

eage[i].flag=1;

ans+=eage[i].len;

count++;

}

return ans;

}

int main()

{

int T;

int z,i;

int a,b,c;

int ans,t_ans;

int del[111],k;

int flag;

int temp;

scanf("%d",&T);

while(T--)

{

scanf("%d%d",&n,&m);

//m e n v

build(n);

for(i=0;i<m;i++)

{

scanf("%d%d%d",&a,&b,&c);

eage[i].a=a;

eage[i].b=b;

eage[i].len=c;

eage[i].flag=0;

}

qsort(eage,m,sizeof(eage[0]),cmp);

ans=Kruskal(-1);

temp=0;

for(i=1;i<=n;i++)if(set[i]==i)   temp++;

if(temp>1)   {printf("0\n");continue;}

k=0;

for(i=0;i<m;i++) if(eage[i].flag)     del[k++]=i;

flag=0;

for(z=0;z<k;z++)

{

build(n);

t_ans=Kruskal(del[z]);

temp=0;

for(i=1;i<=n;i++)if(set[i]==i)   temp++;

if(temp>1)   continue;

if(t_ans==ans)    {flag=1;break;}

}

if(flag)   printf("Not
Unique!\n");

else       printf("%d\n",ans);

}

return 0;

}

经典问题:对于每一条边存在两个权值,分别是花费和长度,要生成一个树,使得总的花费比上总的长度最小。

13、最优比率生成树
(最优比例生成树)

/*

4(v)

x y z

0 0 0

0 1 1

1 1 2

1 0 3

0

cost[i][j]=cost[j][i]=abs(z[i]-z[j]);//花费为海拔之差

dist[i][j]=dist[j][i]=sqrt(t);//距离为 点与点的水平距离

output: the minimum ratio ofoverall cost of the channels to the total length

*/

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

#include<queue>

using namespace std;

#define N 1010

#define MAX 999999999

const double eps=1e-4;

int n;

int vis[N],x[N],y[N],z[N],pre[N];

double dis[N],cost[N][N],dist[N][N];

double prim(double x){

double totalcost=0,totaldist=0;

for(int i=1;i<=n;i++){

pre[i]=1;

}

dis[1]=0;

memset(vis,0,sizeof(vis));

vis[1]=1;

for(int i=2;i<=n;i++){

dis[i]=cost[1][i]-dist[1][i]*x;

}

int k;

for(int i=2;i<=n;i++){

double mincost=MAX;

for(int j=2;j<=n;j++){

if(!vis[j]&&dis[j]<mincost){

mincost=dis[j];

k=j;

}

}

vis[k]=1;

totalcost+=cost[pre[k]][k];

totaldist+=dist[pre[k]][k];

for(int j=1;j<=n;j++){

if(!vis[j]&&dis[j]>cost[k][j]-dist[k][j]*x){

dis[j]=cost[k][j]-dist[k][j]*x;

pre[j]=k;

}

}

}

return totalcost/totaldist;

}

int main(){

while(scanf("%d",&n),n){

for(int i=1;i<=n;i++){

scanf("%d%d%d",&x[i],&y[i],&z[i]);

for(intj=1;j<i;j++){

doublet=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);

cost[i][j]=cost[j][i]=abs(z[i]-z[j]);//花费为海拔之差

dist[i][j]=dist[j][i]=sqrt(t);//距离为
点与点的水平距离

}

}

double a=0;

while(1){

double b=prim(a);

if(abs(a-b)<eps)break;

else a=b;

//cout<<a<<endl;

}

printf("%.3f\n",a);

}

return 0;

}

14、判断边与一个图最小生成shu的关系

题意:给出一张带权无向图,然后询问该图的每条边进行询问,若这条边出现在该图的所有最小生成树中,输出any;若这条边可以出现在这张图的某几个最小生成树中,输出at
least once;若这条边不会出现在这张图的任意一个最小生成树中,输出none。

/*

input

4 5

1 2 101

1 3 100

2 3 2

2 4 2

3 4 1

output

none

any

at least one

at least one

any

*/

#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

#define maxn 100010

using namespace std;

struct Edge{

int from,to,dist,id;

}a[maxn];

int first[maxn],v[maxn*2],next[maxn*2],id[maxn*2];

int ans[maxn],fa[maxn],pre[maxn],dfs_clock,e;

int cmp(Edge a,Edge b){

return a.dist < b.dist;

}

void init(){

e = 0;

memset(first,-1,sizeof(first));

}

void add_edge(int a,int b,int ID){

v[e] = b;

next[e] = first[a];

id[e] = ID;

first[a] = e++;

}

int dfs(int u,int fa_id){

int lowu = pre[u] =++dfs_clock;

for(int i = first[u];i != -1;i= next[i]){

if(!pre[v[i]]){

int lowv =dfs(v[i],id[i]);

lowu = min(lowu,lowv);

if(lowv >pre[u])  ans[id[i]]
= 1;

}else if(pre[v[i]] <pre[u] && id[i] != fa_id){

lowu =min(lowu,pre[v[i]]);

}

}

return lowu;

}

int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}

void join(int x,int y){

int fx = find(x);

int fy = find(y);

if(fx != fy){

e = 0;

first[fx] = first[fy] = -1;

pre[fx] = pre[fy] = 0;

fa[fx] = fy;

}

}

int main()

{

int n,m;

scanf("%d%d",&n,&m);

init();

for(int i = 1;i <=n;i++)  fa[i]
= i;

dfs_clock = 0;

for(int i = 0;i < m;i++){

scanf("%d%d%d",&a[i].from,&a[i].to,&a[i].dist);

a[i].id = i;

}

sort(a,a+m,cmp);

memset(pre,0,sizeof(pre));

memset(ans,0,sizeof(ans));

for(int i = 0;i < m;i++){

int j = i+1;

while(j < m &&a[i].dist == a[j].dist)   j++;

for(int k = i;k <j;k++){

int fx =find(a[k].from);

int fy = find(a[k].to);

if(fx != fy){

add_edge(fx,fy,a[k].id);

add_edge(fy,fx,a[k].id);

ans[a[k].id] = 2;

}

}

for(int k = i;k <j;k++){

int fx =find(a[k].from);

int fy = find(a[k].to);

if(fx != fy &&!pre[fx]){

dfs(fx,-1);

}

}

for(int k = i;k <j;k++){

join(a[k].from,a[k].to);

}

i = j - 1;

}

for(int i = 0;i < m;i++){

if(ans[i] == 0)printf("none\n");

else if(ans[i] == 1)   printf("any\n");

else   printf("at
least one\n");

}

return 0;

}

15、hdu
3371 最小生成树(有重边)

/*

the cities are signed from 1 to n.

1

6( survived cities) 4(you can choose to connect the cities ) 3(stillconnected cities)

it takes c to connect p and q

p q c

1 4 2

2 6 1

2 3 5

3 4 33

the number of this connected citie(2ge 2ge 3ge)

2 1 2

2 1 3

3 4 5 6

Output

For each case, output the least money you need to take, if it’s impossible, just
output -1.

*/

#include<stdio.h>

#include<string.h>

#include<algorithm>

using namespace std;

int n,m,k,p[505],ans;

struct node{

int u,v,w;

}pt[250000];

int cmp(node a,node b)

{

return a.w<b.w;

}

int find(int x){return p[x]==x?x:p[x]=find(p[x]);}

int main()

{

int t;

scanf("%d",&t);

while(t--)

{

int i,j,num,a,b,root,x,y;

for(i=0;i<=500;i++)p[i]=i;

bool flag=false;

scanf("%d%d%d",&n,&m,&k);

for(i=1;i<=m;i++)scanf("%d%d%d",&pt[i].u,&pt[i].v,&pt[i].w);

sort(pt+1,pt+m+1,cmp);

for(i=1;i<=k;i++)

{

scanf("%d%d",&num,&root);

for(j=1;j<num;j++)

{

scanf("%d",&a);

x=find(a),y=find(root);

if(x!=y) p[x]=y;

}

}

for(num=0,i=1;i<=n;i++)if(p[i]==i) num++;

for(ans=0,i=1;i<=m;i++)

{

x=find(pt[i].u);y=find(pt[i].v);

if(x!=y)

{

p[x]=y;

ans+=pt[i].w;num--;

}

if(num==1)

{

flag=true;

break;

}

}

if(flag)printf("%d\n",ans);

elseprintf("-1\n");

}

return 0;

}

二、二分图

1、两列相同数的最大匹配数(月老的难题)

/*

1

3(3男3女)
4(可能关系)

(男女)

1 1

1 3

2 2

3 2

*/

#include<cstdio>

#include<cstring>

using namespace std;

#define N 10010

#define M 510

int head[M], next[N], key[N], num;

int match[M];

bool use[M];

void add(int u, int v) //hash表存图

{

key[num] = v;

next[num] = head[u];

head[u] = num++;

}

bool find(int u) //匈牙利算法

{

int temp;

for(int i = head[u]; i != -1;i = next[i])

{

temp = key[i];

if(!use[temp])

{

use[temp] = true;

if(match[temp]== -1 || find(match[temp])) //增广路

{

match[temp]= u;

returntrue;

}

}

}

return false;

}

int sum(int n) //最大匹配数

{

int sumall = 0;

for(int i = 1; i <= n;++i)

{

memset(use, false,sizeof(use));

if(find(i))

sumall++;

}

return sumall;

}

int main()

{

int ncase;

int allnum, relation;

int u, v;

scanf("%d",&ncase);

while(ncase--)

{

num = 0;

memset(head, -1,sizeof(head));

memset(match, -1,sizeof(match));

scanf("%d%d",&allnum, &relation);

for(int i = 0; i <relation; ++i)

{

scanf("%d%d",&u, &v);

add(u, v);

}

printf("%d\n",sum(allnum));

}

return 0;

}

三、树状数组+线段树组

/*

1、士兵杀敌<1>(树状数组模板)

/*

5(士兵数) 2(询问数)

第i个人杀的人数ai

1 2 3 4 5

第m号到第n号士兵的总杀敌数

1 3

2 4

*/

#include<iostream>

#include<cstdio>

using namespace std;

int C[1000006];//保存树状数组

int n;//元素个数(即节点个数),下标从1开始

//求最小幂2的k次幂

int lowbit(int t){ return t&(t^(t-1)); }

//求前n项和

int sum(int end)

{

int sum=0;

while(end>0)

{

sum+=C[end];

end-=lowbit(end);//或也可end^=Lowbit(end);

}

return sum;

}

//对某个元素进行加减法操作

void Plus(int pos,int num)

{

while(pos<=n)

{

C[pos]+=num;

pos+=lowbit(pos);

}

}

int main()

{

int zishu,i;

scanf("%d%d",&n,&zishu);

for(i=1;i<=n;++i)

{

int temp;

scanf("%d",&temp);//输入原始序列的第i个元素

Plus(i,temp);//
第i个元素在原来为零的基础上加上temp

}

while(zishu--)

{

int min,max;

scanf("%d%d",&min,&max);

printf("%d\n",sum(max)-sum(min-1));

}

return 0;

}

2、士兵杀敌<2>(树状数组模板)

/*

5(士兵) 6(询问)

每个士兵的杀人个数

1 2 3 4 5

QUERY 1 3

ADD 1 2

QUERY 1 3

ADD 2 3

QUERY 1 2

QUERY 1 5

*/

#include<iostream>

#include<cstdio>

using namespace std;

int C[1000006];//保存树状数组

int n;//元素个数(即节点个数),下标从1开始

//求最小幂2的k次幂

int lowbit(int t){ return t&(t^(t-1)); }

//求前n项和

int sum(int end)

{

int sum=0;

while(end>0)

{

sum+=C[end];

end-=lowbit(end);//或也可end^=Lowbit(end);

}

return sum;

}

//对某个元素进行加减法操作

void Plus(int pos,int num)

{

while(pos<=n)

{

C[pos]+=num;

pos+=lowbit(pos);

}

}

int main()

{

int zishu,i;

scanf("%d%d",&n,&zishu);

for(i=1;i<=n;++i)

{

int temp;

scanf("%d",&temp);//输入原始序列的第i个元素

Plus(i,temp);//
第i个元素在原来为零的基础上加上temp

}

while(zishu--)

{

int min,max;

char ch[10];

scanf("%s %d%d",ch,&min,&max);

if(ch[0]==‘Q‘)

printf("%d\n",sum(max)-sum(min-1));

else

Plus(min,max);

}

return 0;

}

3、士兵杀敌(三)(rmq求区间最大最小值之差)

/*

5 2

1 2 6 9 3

第一个数到第二个数之间最大最小值之差

1 2

2 4

*/

#include<cstdio>

#include<algorithm>

#include<cmath>

using namespace std;

const int N = 100010;

int maxsum[20][N], minsum[20][N]; //优化1

void RMQ(int num) //预处理->O(nlogn)

{

for(int i = 1; i != 20; ++i)

for(int j = 1; j <=num; ++j)

if(j + (1<< i) - 1 <= num)

{

maxsum[i][j]= max(maxsum[i - 1][j], maxsum[i - 1][j + (1 <<
i >> 1)]); //优化2

minsum[i][j] = min(minsum[i - 1][j],minsum[i - 1][j + (1 << i >> 1)]);

}

}

int main()

{

int num, query;

int src, des;

scanf("%d %d",&num, &query);

for(int i = 1; i <= num;++i) //输入信息处理

{

scanf("%d",&maxsum[0][i]);

minsum[0][i] = maxsum[0][i];

}

RMQ(num);

while(query--) //O(1)查询

{

scanf("%d%d", &src, &des);

int k = (int)(log(des- src + 1.0) / log(2.0));

int maxres =max(maxsum[k][src], maxsum[k][des - (1 << k) + 1]);

int minres =min(minsum[k][src], minsum[k][des - (1 << k) + 1]);

printf("%d\n",maxres - minres);

}

return 0;

}

4、第i个人的军功数

/*

4 (指令) 10(士兵)

起始时所有人的军功都是0.

ADD 1 3 10  //ADD 1 3 10表示,第1个人到第3个人请战,最终每人平均获得了10军功

QUERY 3

ADD 2 6 50

QUERY 3     //QUERY 3
表示南将军在询问第3个人的军功是多少。

样例输出

10

60

*/

#include<cstdio>

#include<cstring>

const int M=1000010;

int data[M];

int Max;

inline int LowBit(int n)

{

return n&(-n);

}

void Plus(int n,int value) //前n项每项增加value

{

while(n>0)

{

data[n]+=value;

n-=LowBit(n);

}

}

int Get(int n) //获取每个位置的值

{

int sum=0;

while(n<=Max)

{

sum+=data[n];

n+=LowBit(n);

}

return sum;

}

char cmd[50];

int main()

{

int n,a,b,v;

scanf("%d%d",&n,&Max);

while(n--)

{

scanf("%s",cmd);

if(!strcmp(cmd,"ADD"))

{

scanf("%d%d%d",&a,&b,&v);

Plus(a-1,-v);

Plus(b,v);

}

else

{

scanf("%d",&a);

printf("%d\n",Get(a));

}

}

}

五、快排

1、数组排序(快速排序稳定)

#include<iostream>

#include<cstring>

#include<cstdio>

#include<cmath>

using namespace std;

const int N = 10;

int arr[N];

/******************快速排序稳定版本*************************************/

void QuickSort(int low, int high)

{

if(low >= high)

return ;

int i, j, pivot;

i = low, j = high, pivot =arr[(high + low) >> 1]; //每次取中间元素作为基准

swap(arr[low], arr[(high +low) >> 1]);

while(i < j)

{

while(i < j&& arr[j] >= pivot) --j;

arr[i] = arr[j];

while(i < j&& arr[i] <= pivot) ++i;

arr[j] = arr[i];

}

arr[i] = pivot;

QuickSort(low, i - 1); //递归左边

QuickSort(j + 1, high); //递归右边

}

2、快速排序一般版本(可求第K大元素)

int Partition(int low, int high)

{

int i, j, pivot;

i = low, j = high, pivot =arr[low];

while(i < j)

{

while(i < j&& arr[j] >= pivot) --j;

if(i < j)swap(arr[i++], arr[j]);

while(i < j&& arr[i] <= pivot) ++i;

if(i < j)swap(arr[i], arr[j--]);

}

return j; //返回基准元素位置

}

void Quick_Sort(int low, int high)

{

int pivotpos;

if(low < high)

{

pivotpos =Partition(low, high);

Quick_Sort(low,pivotpos - 1); //基准左递归排序

Quick_Sort(pivotpos +1, high); //基准右递归排序

}

}

int select(int low, int high, int k)

{

int pivotpos, num;

if(low == high)

return arr[high];

pivotpos = Partition(low,high);

num = pivotpos - low + 1; //左边元素个数

if(k == num)

return arr[pivotpos];

else if(k < num)

return select(low,pivotpos - 1, k);

else

return select(pivotpos+ 1, high, k - num);

}

/*************************************************************************/

int main()

{

int k;

cout<<"输入10个数字:"<<endl;

for(int i = 0; i < 10;++i)

scanf("%d",&arr[i]);

QuickSort(0, 9);

cout<<"快速排序后:"<<endl;

for(int i = 0; i < 10;++i)

cout<<arr[i]<<"";

cout<<endl;

cout<<"输入第K大元素:"<<endl;

cin>>k;

cout<<select(0, 9,k)<<endl;

return 0;

}

3归并排序求逆序数

#include <cstdio>  

  

int left[250003], right[250003];  

__int64 count;  

  

void merge(int a[], int l, int m, int r)  

{  

    int i, j, k, n1, n2;  

  

    n1 = m - l + 1;  

    n2 = r - m;  

    for (i = 0; i < n1; i++)  

        left[i] = a[l+i];  

    for (i = 0; i < n2; i++)  

        right[i] = a[m+i+1];  

    left[n1] = right[n2] = 0x7fffffff;  

  

    i = j = 0;  

    for (k = l; k <= r; k++)  

    {  

        if (left[i] <= right[j])  

        {  

            a[k] = left[i++];  

        }  

        else  

        {  

            a[k] = right[j++];  

            count += n1 - i;   

        }  

    }  

}  

  

void mergeSort(int a[], int l, int r)  

{  

    if (l < r)  

    {  

        int m = (l + r) / 2;  

        mergeSort(a, l, m);  

        mergeSort(a, m+1, r);  

        merge(a, l, m, r);  

    }  

}  

  

int main()  

{  

    int n, a[500001];  

  

    while (scanf("%d", &n) && n)  

    {  

        count = 0;  

        for (int i = 0; i < n; i++)  

            scanf("%d", &a[i]);  

        mergeSort(a, 0, n-1);  

        printf("%I64d\n", count);  

    }  

}  
 

4、求第k大的数

#include<queue>

#include<iostream>

#include<vector>

using namespace std;

struct mycmp

{

    bool operator()(const int &a,const int &b)

    {

        return a>b;

    }

};//这里表示从小到大排列,最小的数在队头,随时准备走出队列

int main()

{

    int n,k,val;

    char str[5];

    int count;

    while(scanf("%d%d",&n,&k)!=EOF)

    {

        priority_queue<int,vector<int>,mycmp> pq;

        while(n--)

        {

            scanf("%s",str);

            if(str[0]==‘I‘)

            {

                scanf("%d",&val);

                pq.push(val);

                while(pq.size()>k)

                    pq.pop();

            }

            else 

            {

                printf("%d\n",pq.top());

            }

        }

    }

    return 0;

}

5、RMQ模板
,返回区间最值 、 最值的下标

#include<string.h>

#include<stdio.h>

#include<math.h>

const int MAX=200005;

int min(int a,int b){return a<b?a:b;}

int dp[MAX][20],a[MAX];

int n,k,val[MAX];

int  LOG[MAX];

void Make_Rmq(int n,int b[])

{

    int i,j;

    for(i=1;i<=n;i++)

        dp[0][i]=b[i];

    for(i=1;i<=LOG[n];i++)

    {

        int limit=n+1-(1<<i);

        for(j=1;j<=limit;j++)

            dp[i][j]=min(dp[i-1][j],dp[i-1][j+(1<<i>>1)]);

    }

}

int RMQ(int l,int r)

{

    int  k=LOG[r-l+1];

    return min(dp[k][l],dp[k][r-(1<<k)+1]);

}

void Make_Rmqindex(int n,int b[])

{

    int i,j;

    for(i=1;i<=n;i++)

        dp[0][i]=i;

    for(i=1;i<=LOG[n];i++)

    {

        int limit=n+1-(1<<i);

        for(j=1;j<=limit;j++)

        {

            int x=dp[i-1][j],y=dp[i-1][j+(1<<i>>1)];

            dp[i][j]=b[x]<b[y]?x:y;

        }

    }

}

int Rmq_Index(int l,int r,int b[])

{

    int k=LOG[r-l+1];

    int x=dp[k][l];

    int y=dp[k][r-(1<<k)+1];

    return b[x]<b[y]?x:y;

}

int main()

{

    int t,i,j;

    LOG[0]=-1;

    for(i=1;i<MAX;i++)

        LOG[i]=LOG[i>>1]+1;

    for(i=1;i<=10;i++)

            val[i]=i;

    Make_Rmqindex(10,val);

    int l,r;

    while(1)

    {

        scanf("%d%d",&l,&r);//l<r

        int ans=Rmq_Index(l,r,val);

        printf("%d\n",ans);

    }

    return 0;

}

 

 

6快速幂求余模板

经改进后代码如下:(输入a,k,m,求a^k%m)

long f(long a,longk,long m)

{

long b=1;

while(k>=1)

{

if(k%2==1) b=a*b%m;

a=a*a%m;

k=k/2;

}

return b;

}

7、最长公共子序列

/*

最长公共子序列:输出s1和s2的最长公共子序列
不一定连续 如 abcde aafe 则结果为ae

*/

#include <stdio.h>

#include <string.h>

#define MAXLEN 3000//输入的字符串的最大长度

char x[MAXLEN];

char y[MAXLEN];

int b[MAXLEN][MAXLEN];//b存的是方向 用来辅助输出最后的公共字串

int c[MAXLEN][MAXLEN];//c[i][j]表示s1前i个字符和s2前j个字符的最长公共子序列

void LCSLength(int n, int m)

{

int i, j;

for(i = 0; i <= n; i++)

c[i][0] = 0;

for(j = 1; j <= m; j++)

c[0][j] = 0;

for(i = 1; i<= n; i++)

{

for(j = 1; j <= m; j++)

{

if(x[i-1] == y[j-1])//2者相等的时候则此时 c[i][j]
=c[i-1][j-1] + 1;

{

c[i][j] =c[i-1][j-1] + 1;

b[i][j] = 0;

}

else if(c[i-1][j] >=c[i][j-1])//如果不相等
则c[i][j]的值取c[i][j-1],c[i-1][j]中最大的

{

c[i][j] =c[i-1][j];

b[i][j] = 1;

}

else

{

c[i][j] =c[i][j-1];

b[i][j] = -1;

}

}

}

}

void FindLCS(int i, int j)//递归输出最长公共子序列

{

if(i == 0 || j == 0)

return;

if(b[i][j] == 0)

{

FindLCS(i-1,j-1);

printf("%c",x[i-1]);

}

else if(b[i][j] == 1)

FindLCS(i-1,j);//如果是标记为1 则剩余的未输出字符
从s1的前i-1个
s2的前j个中找出来 当递归到标记为0的时候就可以输出了

else

FindLCS(i,j-1);

}

int main(int argc, char **argv)

{

while(scanf("%s %s",x,y)!=EOF)

{

int m,n;

n = strlen(x);

m = strlen(y);

LCSLength(n,m);

FindLCS(n,m);

//printf("%d",c[n][m]);//输出公共串的最长的长度

printf("\n");

}

return 0;

}

8、快速查找素数

#include<stdio.h>

#include<string.h>

#define MAX 2000001

#define MAX_PRIME 2000001

bool nums[MAX];

int prime[MAX_PRIME];

void MakePrime()

{

int i,j;

int pl=0;

nums[0]=1,nums[1]=1;

memset(prime,true,sizeof(prime));

for(i=2;i<MAX;i++)

{

if(!nums[i])

prime[pl++]=i;

for(j=0;j<pl&&i*prime[j]<=MAX;j++)

{

nums[i*prime[j]]=1;

if(!(i%prime[j]))

break;

}

}

}

int main()

{

int n,j;

MakePrime();

while(scanf("%d",&n)!=EOF)

{

if(n>1)

{

printf("2");

for(j=1;prime[j]<=n;j++)

{

printf("%d",prime[j]);

}

}

printf("\n");

}

return 0;

}

9、表达式求值

/*

3

add(1,2)

max(1,999)

add(min(1,1000),add(100,99))

*/

#include<cstdio>

#include<iostream>

using namespace std;

char str[1000];

int start;

int val()

{

intv,n;

switch(str[start])

{

case‘m‘:start+=3;if(str[start-2]==‘i‘) return min(val(),val());else returnmax(val(),val());

case‘a‘:start+=3;return val()+val();

case‘)‘:

case‘(‘:

case‘,‘:++start;return val();

default:sscanf(str+start,"%d%n",&v,&n);start+=n;returnv;

}

}

int main()

{

intn;

scanf("%d",&n);

while(n--)

{

scanf("%s",str);

start=0;

printf("%d\n",val());

}

}

七、二分

int binarysearch(int arr[], int n, int key)

{

int low = 0, high = n;

while(low < high)

{

int mid = low + (high- low) / 2;

if(arr[mid] == key)

{

cout<<"fad";

return mid;

}

else if(arr[mid] >key)

high = mid;

else

low = mid + 1;

}

return -1;

}

八、最短路径

1、最短路径+畅通工程续

每组数据第一行是两个整数N、M(N<=100,M<=10000),

N表示成都的大街上有几个路口,

标号为1的路口是商店所在地,标号为N的路口是赛场所在地,

M则表示在成都有几条路。

N=M=0表示输入结束。

接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。

输入保证至少存在1条商店到赛场的路线。

Output

对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

Sample Input

N(有几个路口) M(有几条路)

nodenum      edgenum

2                1

1 2 3

3 3

1 2 5

2 3 5

3 1 2

0 0

Sample Output

3

2

SPFA版本:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<climits>

#include<queue>

#include<algorithm>

using namespace std;

#define N 110

#define MAX INT_MAX >> 1

#define CLR(arr, what) memset(arr, what, sizeof(arr))

int nodenum, edgenum;

int map[N][N], dis[N];

bool visit[N];

int SPFA(int src, int des)

{

queue<int> q;

CLR(visit, false);

for(int i = 1;i <= nodenum;++i)

dis[i] = MAX;

dis[src] = 0;

visit[src] = true;

q.push(src);

while(!q.empty())

{

int cur = q.front();

q.pop();

visit[cur] = false; //出队标记为false

for(int i = 1; i <=nodenum; ++i)

{

if(dis[i] > dis[cur]+ map[cur][i]) //没有2个集合,和Dijkstra有本质区别

{

dis[i] = dis[cur] +map[cur][i]; //能松弛就松弛

if(!visit[i]) //不在队列中则加入,然后更新所有以前经过此点的最短路径

{

q.push(i);

visit[i] =true;

}

}

}

}

return dis[des];

}

int main()

{

int start, end, cost;

int answer;

while(~scanf("%d%d",&nodenum, &edgenum) && (nodenum + edgenum))

{

for(int i = 1; i <=nodenum; ++i)

for(int j = 1; j <=nodenum; ++j)

map[i][j] = MAX;

for(int i = 0; i <edgenum; ++i)

{

scanf("%d%d%d", &start, &end, &cost);

if(cost <map[start][end])

map[start][end] =map[end][start] = cost;

}

answer = SPFA(1, nodenum);

printf("%d\n",answer);

}

return 0;

}

2、畅通工程再续

/*

3(v) 3(e)

0 1 1

0 2 3

1 2 1

0(sv) 2(ev)

城镇分别以0~N-1编号

如果不存在从S到T的路线,就输出-1.

*/

#include<iostream>

#include<stdio.h>

using namespace std;

#define inf 9999999

int map[250][250];

int n,m;

int Floyd(int x,int y)

{

int t,i,j;

for(t=0;t<n;t++)

for(i=0;i<n;i++)

for(j=0;j<n;j++)

if(map[i][j]>map[i][t]+map[t][j])

{

map[i][j]=map[i][t]+map[t][j];

}

if(map[x][y]==inf) return -1;

else return map[x][y];

}

int main()

{

//n v,m e

while(scanf("%d%d",&n,&m)!=EOF)

{

int a,b,v,d,f,num;

for(int i=0; i<=n; i++)

for(int j=0; j<=n;j++)

map[i][j]=map[j][i]=inf;

for(inti=0;i<n;i++) //注意同一点的权值为0,刚开始wa在这儿

map[i][i]=0;

for(int i=0; i<m; i++)

{

cin>>a>>b>>v;

if(map[a][b]>v)

map[a][b]=map[b][a]=v;

}

cin>>d>>f;

num=Floyd(d,f);

cout<<num<<endl;

}

return 0;

}

3、公交车最短路径(公交站是英文名字)

输入数据有多组,每组的第一行是公交车的总数N(0<=N<=10000);

第二行有徐总的所在地start,他的目的地end;

接着有n行,每行有站名s,站名e,以及从s到e的时间整数t(0<t<100)(每个地名是一个长度不超过30的字符串)。

note:一组数据中地名数不会超过150个。

如果N==-1,表示输入结束。

Output

如果徐总能到达目的地,输出最短的时间;否则,输出“-1”。

Sample Input

6

xiasha westlake

xiasha station 60

xiasha ShoppingCenterofHangZhou 30

station westlake 20

ShoppingCenterofHangZhou supermarket10

xiasha supermarket 50

supermarket westlake 10

-1

#include<iostream>

#include<map>

#include<cstdio>

#include<cstring>

#include<string>

#include<algorithm>

using namespace std;

int dis[155], len[155][155];

bool visit[155];

#define MAX 0x3f3f3f3f

void Dijsktra(int start, int end)

{

int k, temp;

memset(visit, 0,sizeof(visit));

for(int i = start; i <=end; ++i)

dis[i] = (i == start ?0 : MAX); //visit[start] = 1; //如果标记为1,则与temp比较的全都是MAX

for(int i = start; i <=end; ++i)

{

temp = MAX;

for(int j = start; j<= end; ++j)

if(!visit[j]&& dis[j] < temp)

temp =dis[k = j];

visit[k] = 1;

if(temp == MAX) break;

for(int j = start; j<= end; ++j)

if(dis[j] >dis[k] + len[k][j])

dis[j] =dis[k] + len[k][j];

}

}

int main()

{

int num, iterator, distance,flag;

char begin[30], end[30];

char a[30], b[30];

map<string, int>station;

while(scanf("%d",&num) != EOF && num != -1)

{

station.clear();

memset(len, MAX,sizeof(len));

flag = 0;

scanf("%s%s",begin, end);

if(strcmp(begin, end)== 0) flag = 1;

station[begin] = 1;

station[end] = 2;

iterator = 3;

for(int i = 0; i <num; ++i)

{

scanf("%s%s%d",a, b, &distance);

if(!station[a])

station[a]= iterator++;

if(!station[b])

station[b]= iterator++;

len[station[a]][station[b]]= len[station[b]][station[a]] = distance;

}

if(flag)

{

printf("0\n");

continue;

}

Dijsktra(1, iterator);

if(dis[2] == MAX)      printf("-1\n");

elseprintf("%d\n",
dis[2]);

}

return 0;

}

22、最短路径 求最短距离

现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。

Input

N(v)和M(e)(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。

接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。

再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。

Output

对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.

Sample Input

3 3

0 1 1

0 2 3

1 2 1

0 2

3 1

0 1 1

1 2

Sample Output

2

-1

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

#define N 210

#define MAX 9999999

#define CLR(arr, what) memset(arr,what, sizeof(arr))

int num, road;

int dis[N], maze[N][N];

bool visit[N];

void Dijkstra(int start)

{

inttemp, k;

CLR(visit,false);

for(inti = 0; i < num; ++i)

dis[i]= (i == start ? 0 : maze[start][i]);

visit[start]= true;

for(inti = 0; i < num; ++i)

{

temp= MAX;

for(intj = 0; j < num; ++j)

if(!visit[j]&& temp > dis[j])

temp= dis[k = j];

if(temp== MAX)

break;

visit[k]= true;

for(intj = 0; j < num; ++j)

if(!visit[j]&& dis[j] > dis[k] + maze[k][j])

dis[j]= dis[k] + maze[k][j];

}

}

int main()

{

int a, b, cost, start, end;

while(scanf("%d%d", &num, &road) != EOF)

{

for(int i = 0; i < N; ++i)

for(intj = 0; j < N; ++j)

maze[i][j]= MAX;

for(int i = 0; i < road; ++i)

{

scanf("%d%d%d", &a,&b, &cost);

if(cost < maze[a][b]) //一条路可以有多个cost,记录最小的。注意

maze[a][b] = maze[b][a] = cost;

}

scanf("%d%d", &start,&end);

Dijkstra(start);

if(dis[end] == MAX)

printf("-1\n");

else

printf("%d\n",dis[end]);

}

return 0;

}

4、单源最短路Dijkstra算法。只不过起点给你多个,然后求可以到达的目的地中路径最短的一条

6(6条路)
2(和草家相邻城市个数) 3(想去城市的个数)

1 3 5

1 4 7

2 8 12

3 8 4

4 9 12

9 10 2

1 2(和草家相邻)

8 9 10(想去)

输出草儿能去某个喜欢的城市的最短时间

#include<iostream>

#include<cstdio>

#include<cstring>

#include<string>

#include<algorithm>

usingnamespace std;

#defineMAX 0x3f3f3f3f

introad, link, want, total;

intmap[1010][1010], linkarr[1010], wantarr[1010], dis[1010];

boolvisit[1010];

voidDijkstra(int start)

{

int temp, k;

memset(visit, 0, sizeof(visit));

for(int i = 1; i <= total; ++i)

dis[i] = map[start][i];

dis[start] = 0;

visit[start] = 1;

for(int i = 1; i <= total; ++i)

{

temp = MAX;

for(int j = 1; j <= total; ++j)

if(!visit[j] && temp >dis[j])

temp = dis[k = j];

visit[k] = 1;

for(int j = 1; j <= total; ++j)

if(!visit[j] && dis[j] >dis[k] + map[k][j])

dis[j] = dis[k] + map[k][j];

}

}

intmain()

{

int x, y, cost, minn, answer;

while(scanf("%d%d%d", &road,&link, &want) != EOF)

{

total = 0;

memset(map, MAX, sizeof(map));

for(int i = 1; i <= road; ++i)

{

scanf("%d%d%d", &x,&y, &cost);

if(cost < map[x][y])

map[x][y] = map[y][x] = cost;

total = max(total, max(x, y)); //错了N久。。。。因为没有给出点的个数。

}

for(int i = 1; i <= link; ++i) //相连的城市

scanf("%d",&linkarr[i]);

for(int i = 1; i <= want; ++i) //目的地

scanf("%d", &wantarr[i]);

answer = MAX;

for(int i = 1; i <= link; ++i)//linkarr数组中所有元素中到达目的地最短的路

{

Dijkstra(linkarr[i]);

minn = MAX;

for(int j = 1; j <= want; ++j)//linkarr[i]中可以到达的目的地中最短

if(dis[wantarr[j]] < minn)

minn = dis[wantarr[j]];

if(answer > minn)

answer = minn;

}

printf("%d\n", answer);

}

return 0;

}

5、飘谊想知道他走完观光道路并回到源点的最短路径

V e

4 5

1 2 3

2 3 4

3 4 5

1 4 10

1 3 12

#include <stdio.h>

#include <string.h>

#define Maxsize 20

#define FindMin(a,b) a>b?b:a

#define INF 999999999

int g[Maxsize][Maxsize];

int degree[Maxsize];

int count;

int v[Maxsize];

int ans;

int T;

void dfs(int u,int value)

{

int i,j;

if(u==T)

{

ans=FindMin(value,ans);

//         printf("%d%d\n",value);

}

for(i=0;i<count;i++)

{

if(!((u>>i)&1))

{

for(j=i+1;j<count;j++)

if(!((u>>j)&1))

{

intnext=u;

next=next|(1<<i);

next=next|(1<<j);

dfs(next,value+g[v[i]][v[j]]);

}

}

}

}

int main()

{

int n,m;

int u,e,l;

int i,j,k;

int sum=0;

while(~scanf("%d%d",&n,&m))

{

memset(degree,0,sizeof(degree));

for(i=0;i<=n;i++)

for(j=0;j<=n;j++)

g[i][j]=INF;

sum=0;

while(m--)

{

scanf("%d%d%d",&u,&e,&l);

sum+=l;

degree[u]++;degree[e]++;

g[u][e]=g[e][u]=FindMin(g[u][e],l);

}

for(k=1;k<=n;k++)

for(i=1;i<=n;i++)

for(j=1;j<=n;j++)

g[i][j]=FindMin(g[i][j],g[i][k]+g[k][j]);

count=0;

for(i=1;i<=n;i++)

if(degree[i]&1)

v[count++]=i;

T=0;

for(i=0;i<count;i++)

{

T=(T<<1)|1;

}

ans=INF;

dfs(0,0);

printf("%d\n",sum+ans);

}

return 0;

}

6、给多个坐标,求最短路径的最大边

2

0 0(起点)

3 4(终点)

3

17 4

19 4

18 5

0

Sample Output

Scenario #1

Frog Distance = 5.000

Scenario #2

Frog Distance = 1.414

#include<iostream>

#include<cstdlib>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

pair<int ,int> a[200];           //保存n个石头的坐标

double lowcost[200],closet[200];//Prim算法必备,lowcost[i]表示i距离集合的最近距离,closet[i]表示i距离集合最近的点

double map[200][200];           //两点之间的距离

int main()

{

int n;

int k=1;

while(cin>>n,n)

{

int i,j;

for (i = 0 ;i < n ; i++ )

cin>>a[i].first>>a[i].second;   //输入n个点的坐标,从0开始,也就是说题目编程求0-1的最小Frog
Distance

memset(lowcost,0,sizeof(lowcost));   //清零

for ( i = 0 ; i < n ; i ++ )

{

for ( j = 0 ; j < n ; j ++ )

{//求任意两点的距离,保存到map中

map[i][j]=1.0*sqrt(pow(1.0*abs(a[i].first-a[j].first),2)+pow(1.0*abs(a[i].second-a[j].second),2));

}

}

double ans=0.0;//所要求的答案,初始化为0

for ( i = 0 ; i< n ; i++ )

{//把0放入集合,则点到集合的距离此时是点到0的距离

lowcost[i]=map[0][i];

closet[i]=0;

}

for ( i = 0 ; i < n - 1 ; i ++ )

{

doublemindis=1.0*(1<<20);       //点到集合最小距离,初始化为最大

int minone;                       //到集合最小距离对应的点

for ( j = 0 ; j < n ; j ++ )

{

if(lowcost[j]&&mindis>lowcost[j])

{//j点不在集合中,并且j到集合的距离比最小距离还小,则更新最小距离

mindis=lowcost[j];

minone=j;

}

}

if(ans<mindis)       //如果答案并不比更新的最小距离大

ans=mindis;       //更新答案

lowcost[minone]=0.0;//将该点入集合

if(minone==1)       //如果改点是1,则水明义江找到了答案

break;

for ( j = 0 ; j < n ; j ++ )

{//更新各点到集合的最小距离

if(map[j][minone]<lowcost[j])

{//如果minone到某点j的距离比原来的j到集合的距离要小,则更新该点到集合的距离为改点到minone的距离

lowcost[j]=map[j][minone];

closet[j]=minone;

}

}

}

cout<<"Scenario #"<<k<<endl;

printf("Frog Distance = %.3f\n\n",ans);

k++;

}

return 0;

}

7、最k短路

2(v)
2(e)

1 2 5

2 1 4

1(s)
2(end) 2(k)

#include <cstring>

#include <cstdio>

#include <queue>

#define MAXN 1005

#define MAXM 500005

#define INF 1000000000

using namespace std;

struct node

{

int v, w, next;

}

edge[MAXM], revedge[MAXM];

struct A

{

int f, g, v;

bool operator <(const A a)

const

{

if(a.f == f) return a.g < g;

return a.f < f;

}

};

int e, vis[MAXN], d[MAXN], q[MAXM *5];

int

head[MAXN], revhead[MAXN];

int n, m, s, t, k;

void init()

{

e = 0;

memset(head, -1, sizeof(head));

memset(revhead, -1, sizeof(revhead));

}

void insert(int x, int y, int w)

{

edge[e].v = y;

edge[e].w = w;

edge[e].next = head[x];

head[x] = e;

revedge[e].v = x;

revedge[e].w = w;

revedge[e].next =revhead[y];

revhead[y] = e++;

}

void spfa(int src)

{

for(int i = 1; i <= n; i++) d[i] = INF;

memset(vis, 0, sizeof(vis));

vis[src] = 0;

int h = 0, t = 1;

q[0] = src;

d[src] = 0;

while(h < t)

{

int u =

q[h++];

vis[u] = 0;

for(int i = revhead[u] ; i != -1; i
= revedge[i].next)

{

int v = revedge[i].v;

int w = revedge[i].w;

if(d[v] > d[u] + w)

{

d[v] = d[u] + w;

if(!vis[v])

{

q[t++] = v;

vis[v] = 1;

}

}

}

}

}

int Astar(int src, int des)

{

int cnt = 0;

priority_queue<A>Q;

if(src == des) k++;

if(d[src] == INF) return -1;

A t, tt;

t.v = src, t.g = 0, t.f = t.g + d[src];

Q.push(t);

while(!Q.empty())

{

tt = Q.top();

Q.pop();

if(tt.v == des)

{

cnt++;

if(cnt == k) return tt.g;

}

for(int i = head[tt.v]; i != -1; i
= edge[i].next)

{

t.v = edge[i].v;

t.g = tt.g + edge[i].w;

t.f = t.g + d[t.v];

Q.push(t);

}

}

return -1;

}

int main()

{

int x, y, w;

while(scanf("%d%d", &n, &m) != EOF)

{

init();

for(int i = 1; i <= m; i++)

{

scanf("%d%d%d", &x,&y, &w);

insert(x, y, w);

}

scanf("%d%d%d", &s, &t, &k);

spfa(t);

printf("%d\n", Astar(s, t));

}

return 0;

}

/*

8、一棵树上的任意两点的距离

7 6

1 6 13 E

6 3 9 E

3 5 7 S

4 1 3 N

2 4 20 W

4 7 2 S

3

1 6

1 4

2 6

Sample Output

13

3

36

*/

#include<string.h>

#include<stdio.h>

#include<vector>

#include<math.h>

using namespace std;

const int M =40100;

const double inf = 1e20;

int min(int a,int b){return a<b?a:b;}

int n,k,tdfn,tot;

int dp[20][2*M],vis[M];

int B[2*M],LOG[2*M],used[M],F[2*M],pos[M];

vector<pair<int,int> > edge[2*M];

void rmq_init(int n,int num[])

{

inti,j;

for(j=1;j<=n;j++)

dp[0][j]=num[j];

for(j=1;j<=LOG[n];j++)

{

int limit=n+1-(1<<j);

for(i=1;i<=limit;i++)

{

int x=i+(1<<j>>1);

dp[j][i]=min(dp[j-1][x],dp[j-1][i]);

}

}

}

int rmq(int l,int r,int num[])

{

intm=LOG[r-l+1];

return min(dp[m][l],dp[m][r-(1<<m)+1]);

}

int sum[M];

void dfs(int s)

{

inti,t;

used[s]=1;

inttmp=++tdfn;

B[++tot]=tmp;F[tmp]=s;

pos[s]=tot;

for(i=0;i<edge[s].size();i++)

{

t=edge[s][i].first;

if(used[t]) continue;

sum[t]=sum[s]+edge[s][i].second;

dfs(t);

B[++tot]=tmp;//backtrack

}

}

int lca(int a,int b)

{

if(pos[a]>pos[b]) swap(a,b);

intans=rmq(pos[a],pos[b],B);

return F[ans];

}

int main()

{

int i,n,m,a,b,w;

LOG[0]=-1;

for(i=1;i<2*M;i++) LOG[i]=LOG[i>>1]+1;

while(scanf("%d%d",&n,&m)!=EOF)

{

for(i=0;i<=n;i++) edge[i].clear();

char str[5];

for(i=0;i<m;i++)

{

scanf("%d%d%d%s",&a,&b,&w,str);

edge[a].push_back(make_pair(b,w));

edge[b].push_back(make_pair(a,w));

}

sum[1]=0;

tdfn=0;

tot=0;

memset(used,0,sizeof(used));

dfs(1);

rmq_init(tot,B);

scanf("%d",&k);

while(k--)

{

scanf("%d%d",&a,&b);

printf("%d\n",sum[a]+sum[b]-2*sum[lca(a,b)]);

}

}

return 0;

}

9、最短路径spfa

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<climits>

#include<queue>

#include<algorithm>

using namespace std;

#define N 110

#define MAX INT_MAX >> 1

#define CLR(arr, what) memset(arr, what,sizeof(arr))

int nodenum, edgenum;

int map[N][N], dis[N];

bool visit[N];

int SPFA(int src, int des)

{

queue<int> q;

CLR(visit, false);

for(int i = 1;i <= nodenum; ++i)

dis[i] = MAX;

dis[src] = 0;

visit[src] = true;

q.push(src);

while(!q.empty())

{

int cur = q.front();

q.pop();

visit[cur] = false; //出队标记为false

for(int i = 1; i <= nodenum; ++i)

{

if(dis[i] > dis[cur] + map[cur][i])
//没有2个集合,和Dijkstra有本质区别

{

dis[i] = dis[cur] +map[cur][i];
//能松弛就松弛

if(!visit[i]) //不在队列中则加入,然后更新所有以前经过此点的最短路径

{

q.push(i);

visit[i] = true;

}

}

}

}

return dis[des];

}

int main()

{

intstart, end, cost;

intanswer;

while(~scanf("%d%d", &nodenum,&edgenum)
&& (nodenum + edgenum))

{

for(int i = 1; i <= nodenum; ++i)

for(int j = 1; j <= nodenum; ++j)

map[i][j] = MAX;

for(int i = 0; i < edgenum; ++i)

{

scanf("%d%d%d", &start, &end, &cost);

if(cost < map[start][end])

map[start][end] =map[end][start]
= cost;

}

answer = SPFA(1, nodenum);

printf("%d\n", answer);

}

return 0;

}

10、aij矩阵类型的单源最短路径并且输出最短权值和最短路径

/*

起点终点不用tax

5(v)

aij(i到j)

0 3 22 -1 4

3 0 5 -1 -1

22 5 0 9 20

-1 -1 9 0 4

4 -1 20 4 0

各自的tax

5 17 8 3 1

1 3

3 5

2 4

-1 -1

0

*/

#include"stdio.h"

#include"string.h"

int n;

int tax[111];

int map[111][111];

int path[111][111];

void floyd()

{

inttemp;

intk,i,l;

for(i=1;i<=n;i++)

for(l=1;l<=n;l++)

path[i][l]=l;

for(k=1;k<=n;k++)

{

for(i=1;i<=n;i++)

{

for(l=1;l<=n;l++)

{

temp=map[i][k]+map[k][l]+tax[k];

if(temp<map[i][l])

{

map[i][l]=temp;

path[i][l]=path[i][k];

}

elseif(temp==map[i][l])

{

if(path[i][l]>path[i][k])

path[i][l]=path[i][k];

}

}

}

}

}

int main()

{

inti,l;

inttemp;

ints,e;

while(scanf("%d",&n),n)

{

for(i=1;i<=n;i++)

for(l=1;l<=n;l++)

{

scanf("%d",&temp);

if(temp==-1)map[i][l]=11111111;

else              map[i][l]=temp;

}

for(i=1;i<=n;i++)scanf("%d",&tax[i]);

floyd();

while(scanf("%d%d",&s,&e)!=-1)

{

if(s==-1&& e==-1)   break;

printf("From%d to %d :\n",s,e);

printf("Path:%d",s);

temp=s;

while(temp!=e)

{

printf("-->%d",path[temp][e]);

temp=path[temp][e];

}

printf("\n");

printf("Totalcost : %d\n\n",map[s][e]);

}

}

return0;

}

11、邻接矩阵的单源最短路径

/*

5 7

1 2 10

1 4 30

1 5 100

2 3 50

3 5 10

4 3 20

4 5 60

60

*/

#include <iostream>

#include<cstdio>

using namespace std;

#define MAX 9999999

#define LEN 210

int map[LEN][LEN]; //某点到某点两点间的的距离

int dist[LEN]; //记录当前点到源点的最短路径长度

int mark[LEN]; //加入进来的点的集合

//初始化map为正无穷大

void init()

{

int i,j;

for(i=0;i<LEN;i++)

{

for(j=0;j<LEN;j++)

{

map[i][j]=MAX;

}

}

}

//n:多少条路
start:起始点

//dist[i],最后存储着start到i点的最短距离

void myDijstra(int n,int start)

{

int i,j,min,pos;

for(i=1;i<=n;i++)

{

mark[i]=0;//没有点加入

dist[i]=map[start][i];//把start附近点
dis[]初始化

}

mark[start]=1;//把起始点加进来

dist[start]=0;

for(i=1;i<=n;i++)

{

min=MAX;

for(j=1;j<=n;j++)

{

if(!mark[j] &&dist[j]<min)

{ //取出不在mark里的最小的dist[i]

min=dist[j];

pos=j;//标记

}

}

if(min==MAX)//已经不能通了

break;

mark[pos]=1;//把K加进来

//做松弛操作

for(j=1;j<=n;j++)

{

if(!mark[j] &&dist[j]>dist[pos]+map[pos][j])//start->j or start->pos,pos->j

{

dist[j]=dist[pos]+map[pos][j];//这步跟prim算法有点不同

}

}

}

}

int main(){

int i,n,line;

int a,b,d;

scanf("%d%d",&n,&line);//输入点和

init();

for(i=0;i<line;i++)

{

scanf("%d%d%d",&a,&b,&d); //输入各边的权值

// 这个判断是防止重边的,因为也许会对同一条路给出两个值,这时就保存较小的值

if(map[a][b]>d)

{

map[a][b]=map[b][a]=d;

}

}

myDijstra(n,1);//调用方法(点数,起始点)

//输出1到5的最短路径

cout<<dist[5]<<endl;

return 0;

}

九、最大流

1、简单最大流

2

V e

3 2

1 2 1

2 3 1

3 3

1 2 1

2 3 1

1 3 1

#include<iostream>

#include<cstring>

#include<cstdio>

#include<cmath>

#include<queue>

#include<algorithm>

using namespace std;

#define N 100

#define MAX 1<<28

int cost[N][N];

int flow[N], pre[N];

bool visit[N];

int n, m;

int BFS()

{

int temp;

queue<int> q;

visit[1] = true;

memset(pre, -1, sizeof(pre));

memset(visit, false,sizeof(visit));

for(int i = 1; i <= n;++i)

flow[i] = MAX;

q.push(1);

while(!q.empty())

{

temp = q.front();

q.pop();

if(temp == n)

break;

for(int i = 1; i <=n; ++i) //寻找增广路最小流量

{

if(!visit[i]&& cost[temp][i] > 0)

{

visit[i]= true;

flow[i]= min(flow[temp], cost[temp][i]);

pre[i] =temp; //更新路径

q.push(i);

}

}

}

if(!visit[n] || n == 1) //找不到完整增广路or源点汇点重合

return -1;

else

return flow[n];

}

int EK()

{

int temp, d, res, maxflow;

maxflow = 0;

while( (d = BFS() ) != -1)

{

maxflow += d;

temp = n;

while(temp != 1)

{

res =pre[temp];

cost[res][temp]-= d; //正向边

cost[temp][res]+= d; //反向边

temp = res;

}

}

return maxflow;

}

int main()

{

int ncase, T = 1;

int start, end, capacity;

scanf("%d",&ncase);

while(ncase--)

{

memset(cost, 0,sizeof(cost));

// v e

scanf("%d%d", &n, &m);

for(int i = 1; i <=m; ++i)

{

scanf("%d%d%d",&start, &end, &capacity); //重边叠加

cost[start][end]+= capacity;

}

printf("Case %d:%d\n", T++, EK());

}

return 0;

}

2、现在要求从1点到n点在从n点返回1点的最短路

/*

从自己的房子出发到农场,再从农场返回自己的房子,要求去回不走同一条路。

房子的点数为1,农场为n,在1到n之间有很多点,给出n个顶点,m条边,然后m行每行有三个数,

a,b,c代表a到c的路径长度为c,并且a到b是无向边,

现在要求从1点到n点在从n点返回1点的最短路

4v(n) 5e(m)

a b c

1 2 1

2 3 1

3 4 1

1 3 2

2 4 2

*/

/*

Memory 968K

Time   0MS

*/

#include <iostream>

#include <queue>

using namespace std;

#define INF INT_MAX

#define min(a,b) (a>b?b:a)

#define MAXV 1100

#define MAXM 40100

typedef struct{

int s,t,next,w,r;

}Edge;

Edge edge[MAXM];

int source,sink,n,m,mincost,edgesum;

int head[MAXV],d[MAXV],parent[MAXV];

void addedge(int a,int b,int c,int r){

edge[edgesum].s=a;

edge[edgesum].t=b;

edge[edgesum].r=r;

edge[edgesum].w=c;

edge[edgesum].next=head[a];

head[a]=edgesum++;

edge[edgesum].s=b;

edge[edgesum].t=a;

edge[edgesum].r=0;

edge[edgesum].w=-c;

edge[edgesum].next=head[b];

head[b]=edgesum++;

}

int spfa(){

queue <int>q;

int v,i,tmp;

bool vis[MAXV];

for(i=0;i<=sink;i++)d[i]=INF;

memset(vis,false,sizeof(vis));

memset(parent,-1,sizeof(parent));

q.push(source);

vis[source]=true;

d[source]=0;

while(!q.empty()){

v=q.front();q.pop();

vis[v]=false;

for(i=head[v];i!=-1;i=edge[i].next){

tmp=edge[i].t;

if(edge[i].r&& edge[i].w+d[v]<d[tmp]){

d[tmp]=edge[i].w+d[v];

parent[tmp]=i;

if(!vis[tmp]){

q.push(tmp);

vis[tmp]=true;

}

}

}

}

return 0;

}

void MCMF(){

int u;

mincost=0;

while(1){

spfa();

if(parent[sink]==-1)break;

u=parent[sink];        //这里不用求出增光路径上的最小流量

while(u!=-1){             //因为最小流量一定为1

edge[u].r--;

edge[u^1].r++;

u=parent[edge[u].s];

}

mincost+=d[sink];

}

}

int main(){

int i,a,b,c;

while(~scanf("%d%d",&n,&m)){

memset(head,-1,sizeof(head));

edgesum=0,source=0,sink=n+1;

for(i=1;i<=m;i++){

scanf("%d%d%d",&a,&b,&c);

addedge(a,b,c,1);

addedge(b,a,c,1);

}

addedge(source,1,0,2);

addedge(n,sink,0,2);

MCMF();

printf("%d\n",mincost);

}

return 0;

}

十二、贪心问题

4、拦截导弹

#include<stdio.h>

#include<string.h>

int main()

{

intt,n,i,j,maxdp;

scanf("%d",&t);

while(t--)

{

intdp[25]={0},a[25]={0},b[25]={0};

scanf("%d",&n);

for(i=0;i<n;++i)

scanf("%d",&a[i]);

for(i=0,j=n-1;i<n&&j>=0;++i,--j)

b[i]=a[j];

maxdp=0;

for(i=0;i<n;++i)

{

dp[i]=1;

for(j=0;j<i;++j)

{

if(b[i]>b[j]&&dp[i]<dp[j]+1)

dp[i]=dp[j]+1;

}

if(maxdp<dp[i])

maxdp=dp[i];

}

printf("%d\n",maxdp);

}

return0;

}

5、最少拦截系统

#include<iostream>

using namespace std;

int main()

{

int n,i,j,a;

int sum[10002];

while(cin>>n)

{

for(i=0;i<=10001;i++)

sum[i]=400000;

//8 389 207 155 300 299 170 158 65

for(i=0;i<n;i++)

{

cin>>a;

j=0;

while(sum[j]<a)

{

j++;

}

sum[j]=a;

}

int total=0;

for(i=0;i<10001;i++)

if(sum[i]<400000)

total++;

cout<<total<<endl;

}

return 0;

}

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

5、心急的c小佳

if you have five sticks whose pairs oflength and weight are ( 9 , 4 ) , ( 2 , 5 ) , ( 1 , 2 )
, ( 5 , 3 ) , and ( 4 ,1 ) ,

then the minimum setup time should be 2minutes since there is a sequence of pairs ( 4 , 1 ) ,
( 5 , 3 ) , ( 9 , 4 ) ,( 1 , 2 ) , ( 2 , 5 ) .

Sample Input

3

5

4 9 5 2 2 1 3 5 1 4

3

2 2 1 1 2 2

3

1 3 2 2 3 1

Sample Output

2

1

3

#include<iostream>

#include<algorithm>

#include<cstring>

using namespace std;

struct point{

intstart,end;

intvisit;

};

bool cmp(point x,point y)

{

returnx.start<y.start;

}

int main()

{

pointa[5005];

intt,n,i,j,count;

cin>>t;

while(t--)

{

memset(a,0,sizeof(a));

count=0;

j=0;

intkstart,kend;

cin>>n;

for(i=0;i<n;++i)

{

cin>>a[i].start;

cin>>a[i].end;

a[i].visit=1;

}

sort(a,a+n,cmp);

while(count<n)

{

kstart=-1;kend=-1;

for(i=0;i<n;i++)

{

if(a[i].start>=kstart&&a[i].end>=kend&&a[i].visit)//并且没访问过

{

count++;

a[i].visit=0;

kstart=a[i].start;

kend=a[i].end;

}

}

j++;

}

cout<<j<<endl;

}

return0;

}

点评:上面两个题做法是一致的,都是进行标记,进行暴力搜索,很好的贪心的题。

7、radar

/*

题意:给定点集S={(xi,yi)i=1.2.3...n},求用圆心在x轴上,半径为r的圆覆盖S所需的圆的最少个数。

解题思路:先把给定的xi,yi,r转化为x轴上的区间,即圆心所在的区间,这样就转化为了区间选点问题。

先对右端点从小到大排序,右端点相同时,左端点从小到大排序。

*/

#include<cstdio>

#include<algorithm>

#include<cmath>

using namespace std;

struct radar{

doublea,b;

}r[1005];

bool comp(radar a1,radar a2)

{

if(a1.b!=a2.b)//对右端点从小到大排序

returna1.b<a2.b;

returna1.a<a2.a;//右端点相同,左端点从小到大排序

}

int main()

{

intn,d,i,cas=0;

while(scanf("%d%d",&n,&d),n,d)

{

doublex,y;

intflag=0,m=0;

for(i=0;i<n;++i)

{

scanf("%lf%lf",&x,&y);

if(fabs(y)>d)

{

flag=1;//高度大于半径,有覆盖不到的点

continue;

}

doublediff=sqrt(d*d-y*y);

r[m].a=x-diff;

r[m++].b=x+diff;

}

printf("Case%d:
",++cas);

if(flag)

{

printf("-1\n");

continue;

}

sort(r,r+m,comp);

intcnt=1,p=0;

for(i=1;i<m;++i)

{

if(r[i].a<=r[p].b)

{

continue;

//区间重叠,不换
雷达

}

else{

cnt++;

p=i;

}

}

printf("%d\n",cnt);

}

return0;

}

十三、几何问题

1、点线距离

inline double PPdis(Point a,Point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
inline double PLdis(Point a,Point l1,Point l2){
    return fabs(Cross(a,l1,l2)/PPdis(l1,l2));
}

2、是否是凸多边形

inline int _sgn(double x){return fabs(x) < eps ? 0 : (x > 0 ? 1 : 2);}int is_convex(int n,Point P[]){//允许相邻边共线,顶点按顺时针或者逆时针给出
    int i,s[3]={1,1,1};
    for(i=0;i<n&&s[1]|s[2];i++)
        s[_sgn(Cross(P[i],P[(i+1)%n],P[(i+2)%n]))]=0;
    return s[1]|s[2];
}

3、点是否在凸多边形内或边上

int inside_convex(Point q,int n,Point *p){
    int i,s[3]={1,1,1};
    for(i=0;i<n&&s[1]|s[2];i++)
        s[_sgn(Cross(p[i],p[(i+1)%n],q))]=0;
    return s[1]|s[2];
}

4、点在任意多边形内或边上

#include <math.h>
#include <cstdio>
#include<algorithm>using namespace std;const  int maxn = 100010;const double eps = 1e-8;
inline double sgn(double x) {return fabs(x)<eps?0:(x>0?1:-1);}struct point{
    double x,y;
    bool operator == (const point& t) const {
        return sgn(x-t.x)==0 && sgn(y-t.y)==0;
    }
}p[maxn],set[maxn];
inline double cross(point a,point b,point c){return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);}bool dotOnSeg(point p, point s, point e) {                
    if ( p == s || p == e )     return true;
    return sgn(cross(s,e,p))==0 && sgn((p.x-s.x)*(p.x-e.x))<=0 && sgn((p.y-s.y)*(p.y-e.y))<=0;
} bool point_in_polygon(point o, point* p, int n) {
    int i, t;
    point a, b;
    p[n] = p[0];    t = 0;
    for (i=0; i < n; i++) {
        if ( dotOnSeg(o, p[i], p[i+1]) )        return true;
        a = p[i]; b = p[i+1];
        if ( a.y > b.y ) {
            point tmp = a; a = b; b = tmp;
        }
        if ( cross(o, a, b) < -eps && a.y < o.y-eps && o.y < b.y+eps )
            t++;
    }
    return t&1;
}
 
 

十四、kmp算法

1、最小的匹配位置

/*

a[1], a[2], ...... , a[N]

b[1], b[2], ...... , b[M]

存在k使得: a[K] = b[1], a[K + 1] = b[2],
...... ,a[K + M - 1] = b[M]

If there are more than one K exist, output the smallest one.

2(组数)

13 5

1 2 1 2 3 1 2 3 1 3 2 1 2

1 2 3 1 3

*/

#include<cstdio>

#include<cstring>

int n,m;

int a[1000010],b[10010];

int p[11111];

void getp(){

p[1]=0;

int i,j=0;

for(i=2;i<=m;i++){

while(j>0&&b[j+1]!=b[i]) j=p[j];

if(b[j+1]==b[i]) j+=1;

p[i]=j;

}

}

int kmp()

{

int i,j=0,cnt=0;

for(i=1;i<=n;i++){

while(j>0&&b[j+1]!=a[i]) j=p[j];

if(b[j+1]==a[i]) j+=1;

if(j==m){

return i-j+1;

j=p[j];

}

}

return -1;

}

int main()

{

int t;

scanf("%d",&t);

while(t--)

{

scanf("%d%d",&n,&m);

for(int i=1;i<=n;i++)scanf("%d",&a[i]);

for(intj=1;j<=m;j++) scanf("%d",&b[j]);

getp();

printf("%d\n",kmp());

}

}

2、子串出现的次数

/*

1组数

AZA            w

AZAZAZA        T

3

on a single line: the number of occurrences of the word W in the text T.

*/

#include<cstdio>

#include<cstring>

int n,m;

char a[1000010],b[10010];

int p[11111];

void getp(){

p[1]=0;

int i,j=0;

for(i=2;i<=m;i++){

while(j>0&&b[j+1]!=b[i]) j=p[j];

if(b[j+1]==b[i]) j+=1;

p[i]=j;

}

}

int kmp()

{

int i,j=0,cnt=0;

for(i=1;i<=n;i++){

while(j>0&&b[j+1]!=a[i]) j=p[j];

if(b[j+1]==a[i]) j+=1;

if(j==m){

cnt++;

j=p[j];

}

}

return cnt;

}

int main()

{

int t;

scanf("%d",&t);

while(t--)

{

scanf("%s%s",b+1,a+1);

m=strlen(b+1);

n=strlen(a+1);

getp();

printf("%d\n",kmp());

}

}

3、简单求周期

/*

abcd

aaaa

ababab

1

4

3

*/

#include<cstdio>

#include<cstring>

char b[1000010];

int p[1000010];

int m,n;

void getp(){

p[1]=0;

int i,j=0;

for(i=2;i<=m;i++){

while(j>0&&b[j+1]!=b[i]) j=p[j];

if(b[j+1]==b[i]) j+=1;

p[i]=j;

}

}

int main(){

while(scanf("%s",b+1)!=EOF)

{

if(b[1]==‘.‘) break;

m=strlen(b+1);

getp();

if(m%(m-p[m])==0)printf("%d\n",m/(m-p[m]));

elseprintf("1\n");

}

}

/*

4、求最长的公共子串,要注意的是字典序最小

3

3

CATCATCATCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

ACATCATCATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AACATCATCATTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT

*/

#include<cstdio>

#include<cstring>

char str[20][70];

char tmp[70];

int p[70];

void getp(int m,char *b1){

char b[70];

strcpy(b+1,b1);

p[1]=0;

int i,j=0;

for(i=2;i<=m;i++){

while(j>0&&b[j+1]!=b[i]) j=p[j];

if(b[j+1]==b[i]) j+=1;

p[i]=j;

}

}

bool kmp(char *a1,char *b1,int n,int m)

{

char a[70],b[70];

strcpy(a+1,a1);strcpy(b+1,b1);

int i,j=0,cnt=0;

for(i=1;i<=n;i++){

while(j>0&&b[j+1]!=a[i]) j=p[j];

if(b[j+1]==a[i]) j+=1;

if(j==m){

return true;

}

}

return false;

}

bool check(char *s,int tot)

{

int i,j;

for(i=2;i<=tot;i++)

{

intn=strlen(str[i]+1),m=strlen(s);

if(!kmp(str[i]+1,s,n,m))

return false;

}

return true;

}

char ans[70];

int main()

{

int t,n,i,j;

scanf("%d",&t);

while(t--)

{

scanf("%d",&n);

for(i=1;i<=n;i++)  scanf("%s",str[i]+1);

int len=strlen(str[1]+1);

int L=0;

for(i=1;i<=len;i++)

{

for(j=1;j<=len-i+1;j++)

{

strncpy(tmp,str[1]+j,i);

memset(p,0,sizeof(p));

getp(i,tmp);

if(check(tmp,n))

{

if(i>=L)

{

if(strcmp(tmp,ans)<0&&i==L) strcpy(ans,tmp);

if(i>L)  strcpy(ans,tmp);

L=strlen(ans);

}

}

memset(tmp,0,sizeof(tmp));

}

}

if(L>=3) puts(ans);

else puts("no significantcommonalities");

}

}

5、kmp算法模板(子串个数)

#include<cstdio>

#include<cstring>

int n,m;

char a[1000],b[1000];

int p[1000];

void getp(){

p[1]=0;

int i,j=0;

for(i=2;i<=m;i++){

while(j>0&&b[j+1]!=b[i]) j=p[j];

if(b[j+1]==b[i]) j+=1;

p[i]=j;

}

}

int kmp()

{

int i,j=0,cnt=0;

for(i=1;i<=n;i++){

while(j>0&&b[j+1]!=a[i]) j=p[j];

if(b[j+1]==a[i]) j+=1;

if(j==m){

cnt++;

j=p[j];

}

}

return cnt;

}

int main()

{

while(scanf("%s%s",a+1,b+1)!=EOF)

{

m=strlen(b+1);

n=strlen(a+1);

getp();

printf("%d\n",kmp());

}

}

/*

6、求S中最长回文串的长度.

 
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,
回文就是正反读都是一样的字符串,如aba, abba等
 
aaaa
abab
4
3
*/ 
 
#include<cstdio>
#include<cstring>
const int M = 110010*2;
char str[M];//start from index 1
int p[M];
char s[M];
int n;
void checkmax(int &ans,int b){
    if(b>ans) ans=b;
}
inline int min(int a,int b){
    return a<b?a:b;
}
void kp(){
    int i;
    int mx = 0;
    int id;
    for(i=1; i<n; i++){
        if( mx > i )
            p[i] = min( p[2*id-i], p[id]+id-i );
        else
            p[i] = 1;
        for(; str[i+p[i]] == str[i-p[i]]; p[i]++) ;
        if( p[i] + i > mx ) {
            mx = p[i] + i;
            id = i;
        }
    }
}
void pre()
{
    int i,j,k;
    n = strlen(s);
    str[0] = ‘$‘;
    str[1] = ‘#‘;
    for(i=0;i<n;i++)
    {
        str[i*2 + 2] = s[i];
        str[i*2 + 3] = ‘#‘;
    }
    n = n*2 + 2;
    str[n] = 0;
}
 
void pt()
{
    int i;
    int ans = 0;
    for(i=0;i<n;i++)
        checkmax(ans, p[i]);
    printf("%d\n", ans-1);
}
 
int main()
{
    int T,_=0;
    while( scanf("%s", s) !=EOF )
    {
        pre();
        kp();
        pt();
    }
    return 0;
}
 
 

7、容斥定理

 
/*
 
he wants to fire the people whose work number is co-prime with n next year.
 
2
4
5
 
82
354
Hint
Case1: sum=1+3*3*3*3=82
Case2: sum=1+2*2*2*2+3*3*3*3+4*4*4*4=354
*/
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
const __int64 mod = 1000000007;
__int64 n;
__int64 power(__int64 a,__int64 b,__int64 c)
{
    __int64 ret=1;
    while(b>0)
    {
        if(b&1)
            ret=ret*a%c;
        a=a*a%c;
        b>>=1;
    }
    return ret;
}
__int64  calc(__int64 n)
{
       __int64 a=n,b=(2*n+1),c=(n+1),d=(3*n*n+3*n-1)%mod;
       __int64 sum=1;
       sum*=a;sum%=mod;
       sum*=b;sum%=mod;
       sum*=c;sum%=mod;
       sum*=d;sum%=mod;
       __int64 t=power(30,mod-2,mod);
       return sum*t%mod;
}
__int64 sici(__int64 n)
{
    __int64 sum=1;
    for(int i=1;i<=4;i++)
    {
        sum*=n;
        if(sum>=mod) sum%=mod;
    }
    return sum;
}
__int64 solve(__int64 r,__int64 n)
{
    vector<__int64> p;
    __int64 i;
    for(i=2;i*i<=r;i++)
    {
        if(r%i==0)
        {
            p.push_back(i);
            while(r%i==0) r/=i;
        }
    }
    if(r>1) p.push_back(r);
    __int64 sum=0;
    for(__int64 num=1;num<(1<<p.size());num++)
    {
        __int64 mult=1,ones=0;
        for(i=0;i<p.size();i++)
        {
            if(num&(1<<i))
            {
                ones++;
                mult*=p[i];
                if(mult>=mod) mult%=mod;
            }
        }
        if(ones%2) sum+=sici(mult)*calc(n/mult);
        else sum-=sici(mult)*calc(n/mult);
        sum%=mod;
    }
    return sum;
}
int main()
 {
     __int64 t,i,j;
     scanf("%I64d",&t);
     while(t--)
     {
         scanf("%I64d",&n);
         printf("%I64d\n",(calc(n)-solve(n,n)%mod+mod)%mod);
     }
     return 0;
 }
 
 
/*

8、字典树的简单应用

 
banana
band
bee
absolute
acm
 
ba
b
band
abc
 
2
3
1
0
 
*/
#include<stdio.h>
#include<string.h>
char s[15];
class trie{
public :
    int num;
    trie* child[27];
    trie()
    {
        num=0;
        memset(child,0,sizeof(child));
    }
}root;
void insert(char *s)
{
    class trie *cur=&root;
    int len=strlen(s);
    for(int i=0;i<len;i++)
    {
      int id=s[i]-‘a‘;
      if(!cur->child[id])
          cur->child[id]=new trie;
      cur=cur->child[id];
      cur->num++;
    }
}
int find(char *s)
{
     class trie *cur=&root;
     int len=strlen(s);
     for(int i=0;i<len;i++)
     {
         int id=s[i]-‘a‘;
         if(!cur->child[id]) return 0;
         cur=cur->child[id];
     }
     return cur->num;
}
int main()
{
    while(gets(s))
    {
        if(strcmp(s,"")==0) break;
            insert(s);
    }
    while(scanf("%s",s)!=EOF)
        printf("%d\n",find(s));
    return 0;
}

8、括号匹配

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#define N 10005

char a[10005];

typedef struct{

char*top;

char*base;

intstacksize;

}SqStack;

void InitStack(SqStack *s)

{

s->base=(char*)malloc(N*sizeof(char));

s->top=s->base;

s->stacksize=N;

}

void Push(SqStack *s,char e)

{

*s->top=e;

s->top++;

}

char Pop(SqStack *s)

{

--s->top;

return*s->top;

}

char GetTOP(SqStack *s)

{

return*(s->top-1);

}

int matching(char a[])

{

inti,len;

len=strlen(a);

SqStacks;

InitStack(&s);

for(i=0;i<len;++i)

{

if(a[i]==‘(‘||a[i]==‘[‘)

Push(&s,a[i]);

elseif(a[i]==‘)‘)

{

if(s.top==s.base)

return0;

elseif(GetTOP(&s)==‘(‘)

Pop(&s);

else

return 0;

}

elseif(a[i]==‘]‘)

{

if(s.top==s.base)

return0;

elseif(GetTOP(&s)==‘[‘)

Pop(&s);

else

return 0;

}

}

if(s.top==s.base)

return1;

else

return0;

}

int main()

{

intzushu;

scanf("%d",&zushu);

while(zushu--)

{

scanf("%s",a);

if(matching(a))

printf("Yes\n");

else

printf("No\n");

}

return0;

}

/*

9、求一个字符串的最长递增子序列的长度

如:dabdbf最长递增子序列就是abdf,长度为4

*/

#include<stdio.h>

int length(char * s)

{

intlen[128] = {0}, i, t;

for(;*s != ‘\0‘ && (t = len[*s
- 1] + 1); s++)

for(i= *s; i < 128 && len[i] <
t; len[i++] = t);

returnlen[127];

}

int main()

{

intn;

chars[10001];

for(scanf("%d\n",&n); n--;)

printf("%d\n",length(gets(s)));

return0;

}

时间: 2024-10-28 19:35:37

2016/6/1 第九届ACM大赛前夕模板总结的相关文章

2014年河南省第七届ACM大赛总结

虽然大赛已经结束了两天,不过比赛的场景还是不断地在眼前回放,一遍遍,这次的比赛给了我很深刻的感悟还有教训. 刚开始比赛选择了贩卖武器那道题,也是全场到最后唯一没有被人做出来的一道题,策略的严重错误,大概耽误了1个多小时. 后面发现了此题的难度,于是换了一道题简单题,不过由于测试数据多了一个空格,一直超时,此刻已经受到了比较大的打击,并且心神开始乱了起来,以至于做第二题的时候 一直明白怎么写,却错了好多次,不能静心分析细节,不过后来由于队友的鼓励重新冷静了下来,情况才得以好转,这使我发现了自己的不

ACM大赛题 【C++大数相乘】

题     目: 大数相乘,我们常常会遇见几百位长的数字之间相乘的编程题,例如在算法中,ACM大赛题中,下面就是大数相乘的详细过程. 思      路: 模拟相乘法 举例说明: 123*789=97047 原理展示: 计算机计算: . C++源代码: 结果展示:

河南省第七届ACM大赛成绩

本来不想写这篇文章了,但后来想想还是写了:一为纪念我第一次参加这样一个规模宏大的赛事,二为激励自己争取在明年ACM赛场上取得更好地成绩! 注:考试过程不再详细描述! 队名:逐鹿 队员组成: 队长:许长安 队员:李朋飞   张亚威 队员分工: 统筹:许长安 主力:张亚威 翻译:李朋飞 本次比赛,和队长许长安.队友李朋飞在考场配合比较默契,顺利解决了4道题,以30名的成绩取得银奖! 河南省第七届ACM程序设计大赛最终排名 河南省第六届ACM程序设计大赛最终排名 河南省第七届ACM大赛成绩

2016风云杯大学生信安大赛 WriteUp

2016风云杯大学生信安大赛 web 01 web 02 web 03 web 04 web 05 web 06 web 08 web 09 CRYPTO 01 misc 01 misc 02 misc 03 misc 06 apk 01 apk 03 apk 04 re 01 re 03 re 04 2016风云杯大学生信安大赛 好吧第二次正式打CTF,虽然这次的题比较简单,而且大部分强队都去打whctf去了,最后10分钟直接从第四掉到第七,也没办法,实力不够,继续练吧,贴个图纪念一下.整体看

ACM大赛赛后感想

ACM大赛是每一个学计算机学子展现自我专业水平的一个平台,可以说不入一回ACM赛场,非计控真好汉.早在大一上学期,贺老就告诉我们大一下学期会有这场比赛,但那时好玩,并不是很重视,也不知道大赛任何准备的方向.寒假的时候,一直想做这件事来着的,但同学频繁的约聚,天然的外出好天气,让我渐渐地忘记了这件事,整个寒假一直在放荡自我之中,偶尔看到桌上还放着从学校图书馆带回的几本书,会闲来翻看外,并没做任何有效有意义的事情,对ACM的准备也只停留在想法上.回学校后,登看了csdn,发现一些同学在寒假时果然做到

[ACM] 线段树模板

#include<iostream> #include<cmath> using namespace std; #define maxn 200005 class Node{ public: int l,r; int add;//附加值 int sum; }node[maxn]; int getRight(int n){//获得满足2^x>=n的最小x[从0层开始,给编号获得层数] return ceil(log10(n*1.0)/log10(2.0)); } void bu

2016河南省第九届ACM程序设计竞赛【正式赛真题】

A题:表达式求值 时间限制:1000 ms  |  内存限制:65535 KB 描述 假设表达式定义为:1. 一个十进制的正整数 X 是一个表达式.2. 如果 X 和 Y 是 表达式,则 X+Y, X*Y 也是表达式; *优先级高于+.3. 如果 X 和 Y 是 表达式,则 函数 Smax(X,Y)也是表达式,其值为:先分别求出 X ,Y值的各位数字之和,再从中选最大数.4.如果 X 是 表达式,则 (X)也是表达式.例如:表达式 12*(2+3)+Smax(333,220+280) 的值为 6

长沙理工大学第十二届ACM大赛-重现赛

年轮广场 时间限制:1秒 空间限制:131072K 题目描述 在云塘校区,有一个很适合晒太阳的地方----年轮广场 年轮广场可以看成n个位置顺时针围成一个环. 这天,天气非常好,Mathon带着他的小伙伴们出来晒太阳.他们分别坐在A[i]位置上,每个位置上保证最多只有1个小伙伴.现在Mathon想让大家集合玩狼人杀,所以想选择一个位置集合,之后所有的人顺时针或逆时针移动到那里去,每移动两个相邻的位置需要1个单位时间,小伙伴们都很有素质所以不会插近路踩草坪,只会沿着位置走. Mathon想越快集合

“师创杯”山东理工大学第九届ACM程序设计竞赛

A:签到题,直接LL做 B:模拟.没什么好写的 C:求k * m % n == 0最小的k,k = n / (gcd(n,m)) D:bfs E:把第一和第二棵树hash起来,然后在第一棵树每个节点找一下相等的 F:规律题 考虑len == 1的时候,年份范围是2009 - 2018len == 2的时候年份范围是2019 - 2118..然后递增,l[i] = r[i - 1] + 1,r[i] = l[i] + 10^i - 1.再随便特判一下就做完了 G:题意很迷,题意就是输入一篇文章,可