对于下面的模板题不懂的话--请自学模板---
在我的博客里可能会有讲解---
重点可看:我的ACM历程
Description
今天,它终于当上了梦寐以求的体育课老师。第一次课上,它发现一个有趣的事情。在上课之前,所有同学要排成一列, 假设最开始每个人有一个唯一的ID,从1到 N ,在排好队之后,每个同学会找出包括自己在内的前方所有同学的最小ID,作为自己评价这堂课的分数。麻烦的是,有一些同学不希望某个(些)同学排在他(她)前面,在满足这个前提的情况下,新晋体育课老师——度度熊,希望最后的排队结果可以使得所有同学的评价分数和最大。
Input
对于每组数据,第一行输入两个整数 N 和 M (1 \leq N \leq 100000, 0 \leq M \leq 100000) ,分别表示总人数和某些同学的偏好。
接下来 M 行,每行两个整数 A 和 B(1 \leq A, B \leq N) ,表示ID为 A 的同学不希望ID为 B 的同学排在他(她)之前。你可以认为题目保证至少有一种排列方法是符合所有要求的。
Output
Sample Input
3 1 0 2 1 1 2 3 1 3 1
Sample Output
1 2 6
拓扑水题---
代码:
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int head[120000];
struct node{
int to,next;
}dian[120000];
int shu[120000];
int main()
{
int t;scanf("%d",&t);
for (int ca=1;ca<=t;ca++)
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
head[i]=-1;
shu[i]=0;
}
int a,b;
while (m--)
{
scanf("%d%d",&a,&b);
dian[m].to=b;
dian[m].next=head[a];
head[a]=m;
shu[b]++;
}
priority_queue<int> que;
for (int i=1;i<=n;i++)
if (shu[i]==0)
que.push(i);
__int64 ans=0;
int lp=120000000;
while (!que.empty())
{
a=que.top();
que.pop();
lp=min(lp,a);
ans+=lp;
for (int j=head[a];j!=-1;j=dian[j].next)
{
b=dian[j].to;
shu[b]--;
if (shu[b]==0)
que.push(b);
}
}
printf("%I64d\n",ans);
}
return 0;
}
二分图--模板题---
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int k,n,m;
int head[520];
int fer[520];
bool guo[520];
struct node{
int to,next;
}dian[1200];
int find(int xx)
{
for (int i=head[xx];i!=-1;i=dian[i].next)
{
int v=dian[i].to;
if (guo[v])
{
guo[v]=false;
if (!fer[v])
{
fer[v]=xx;
return true;
}
else if (find(fer[v]))
{
fer[v]=xx;
return true;
}
}
}
return false;
}
int main()
{
while (scanf("%d",&k),k)
{
scanf("%d%d",&m,&n);
memset(fer,0,sizeof(fer));
memset(dian,0,sizeof(dian));
for (int i=0;i<=510;i++)
head[i]=-1;
int a,b;
for (int i=0;i<k;i++)
{
scanf("%d%d",&a,&b);
dian[i].to=b;
dian[i].next=head[a];
head[a]=i;
}
int s=0;
for (int i=1;i<=m;i++)
{
memset(guo,true,sizeof(guo));
if (find(i))
s++;
}
printf("%d\n",s);
}
return 0;
}
Description
现在给出老 Jack农田的数据,你需要告诉老 Jack 在保证所有农田全部可连通灌溉的情况下,最少还需要再购进多长的管道。另外,每块农田都是方形等大的,一块农田只能跟它上下左右四块相邻的农田相连通。
Input







输入包含若干组测试数据,处理到文件结束。每组测试数据占若干行,第一行两个正整数















Output
第一行输出:"Case #i:"。i代表第i组测试数据。
第二行输出 1 个正整数,代表老 Jack 额外最少购进管道的长度。
Sample Input
2 4 3 9 12 4 7 8 56 32 32 43 21 12 12 2 3 34 56 56 12 23 4
Sample Output
Case #1: 82 Case #2: 74
最小生成树---
建边时:重复的变只需要记录一次---(否则超内存)
即只记每个点右边和下边的点---
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL __int64
int n,m;
int xx[2]={0,1};
int yy[2]={1,0};
LL map[1010][1010];
int fer[1001000];
struct node{
int a,b,chang;
}lu[2000100];
bool cmp(node xx,node yy)
{
return xx.chang<yy.chang;
}
int find(int xx)
{
if (xx==fer[xx])
return xx;
return fer[xx]=find(fer[xx]);
}
int main()
{
int t;scanf("%d",&t);
for (int ca=1;ca<=t;ca++)
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%I64d",&map[i][j]);
int now,qian;int x,y,kp=0;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
now=i*m-m+j;
for (int k=0;k<2;k++)
{
x=i+xx[k];y=j+yy[k];
if (x&&y&&x<=n&&y<=m)
{
lu[kp].a=now;
lu[kp].b=x*m-m+y;
lu[kp].chang=abs(map[i][j]-map[x][y]);
kp++;
}
}
}
}
sort(lu,lu+kp,cmp);
for (int i=1;i<=n*m;i++)
fer[i]=i;
LL ans=0;
now=n*m;
for (int i=0;i<kp;i++)
{
x=find(lu[i].a);
y=find(lu[i].b);
if (x!=y)
{
ans+=lu[i].chang;
fer[x]=y;
now--;
if (now==1)
break;
}
}
printf("Case #%d:\n%I64d\n",ca,ans);
}
return 0;
}
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int ru[1400];
int fer[1400];
int find(int xx)
{
if (xx==fer[xx])
return xx;
return fer[xx]=find(fer[xx]);
}
int main()
{
while (scanf("%d",&n),n)
{
scanf("%d",&m);
memset(ru,0,sizeof(ru));
for (int i=1;i<=n;i++)
fer[i]=i;
int a,b,aa,bb;
while (m--)
{
scanf("%d%d",&a,&b);
ru[a]++;ru[b]++;
aa=find(a);
bb=find(b);
if (aa!=bb)
fer[aa]=bb;
}
int s=0,ss=0;
for (int i=1;i<=n;i++)
{
if (find(i)==i)
s++;
if (ru[i]%2!=0)
ss++;
}
if (ss||s!=1)
printf("0\n");
else
printf("1\n");
}
return 0;
}
Description
Input
The labyrinth is designed in such a way that there is exactly one path between any two free blocks. Consequently, if we find the proper hooks to connect, it is easy to find the right path connecting them.
Output
Sample Input
2 3 3 ### #.# ### 7 6 ####### #.#.### #.#.### #.#.#.# #.....# #######
Sample Output
Maximum rope length is 0. Maximum rope length is 8.
Hint
If you use recursion, maybe stack overflow. and now C++/c 's stack size is larger than G++/gcc
树的直径---:
思路:
每一个联通的区域都可以看做是一个树---
然后两次dfs--求树的直径
代码:
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
bool fafe[1010][1010];
char ch[1010][1010];
int shu[1001000],kp;
int xx[4]={0,0,1,-1};
int yy[4]={1,-1,0,0};
int n,m;
int ii,jj;
struct node{
int x,y;
int step;
}now,qian;
int dfs(int i,int j)
{
queue<node> que;
now.x=i;now.y=j;
now.step=0;
que.push(now);
fafe[i][j]=false;
int a,b,ans;
while (!que.empty())
{
now=que.front();
que.pop();
ii=now.x;jj=now.y;
ans=now.step;
for (int k=0;k<4;k++)
{
a=ii+xx[k];b=jj+yy[k];
if (a>0&&b>0&&a<=n&&b<=m&&ch[a][b]=='.'&&fafe[a][b])
{
fafe[a][b]=false;
qian.x=a;qian.y=b;qian.step=now.step+1;
que.push(qian);
}
}
}
return ans;
}
void bfs(int i,int j)
{
ch[i][j]='#';
int a,b;
for (int k=0;k<4;k++)
{
a=i+xx[k];b=j+yy[k];
if (a>0&&b>0&&a<=n&&b<=m&&ch[a][b]=='.')
{
bfs(a,b);
}
}
}
int main()
{
int t;scanf("%d",&t);
while (t--)
{
scanf("%d%d",&m,&n);
for (int i=1;i<=n;i++)
scanf("%s",ch[i]+1);
kp=0;int sss=0,ss;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
if (ch[i][j]=='.')
{
memset(fafe,true,sizeof(fafe));
dfs(i,j);
memset(fafe,true,sizeof(fafe));
ss=dfs(ii,jj);
sss=max(sss,ss);
bfs(i,j);
}
}
}
printf("Maximum rope length is %d.\n",sss);
}
return 0;
}
Description
Input
接下来的M行里,每行包括3个整数a,b,c.代表a和b之间有一条通路,并且需要花费c元(c <= 100)。
Output
Sample Input
3 3 1 2 1 2 3 1 1 3 1 3 3 1 2 1 1 2 3 2 3 1
Sample Output
3 It's impossible.
求图中的最小环:
思路1:对于每一边A-B进行覆盖处理:
将此边覆盖--然后求A到B的最短距离:
时间复杂度为:O(n*n*m)
思路2:
Floyd的一点点变形求最小环---【模板】----
时间复杂度:O(n*n*n)
下面用的是思路1---
思路2正在学---
代码“:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
int map[110][110];
int dis[110];
bool fafe[110];
int disk(int xx,int yy)
{
int ans=-1;
memset(fafe,true,sizeof(fafe));
for (int i=1;i<=n;i++)
dis[i]=map[xx][i];
fafe[xx]=false;
fafe[yy]=false;
while (1)
{
int mi=0xff3f3f,ii=-1;
for (int i=1;i<=n;i++)
{
if (fafe[i]&&dis[i]<mi)
{
mi=dis[i];
ii=i;
}
}
if (ii==-1)
break;
fafe[ii]=false;
if (map[ii][yy]<10000)
{
if (ans==-1)
ans=mi+map[ii][yy];
else
ans=min(ans,mi+map[ii][yy]);
}
for (int i=1;i<=n;i++)
{
if (fafe[i]&&map[ii][i]+dis[ii]<dis[i])
dis[i]=dis[ii]+map[ii][i];
}
}
return ans;
}
int main()
{
while (~scanf("%d%d",&n,&m))
{
int a,b,c;
memset(map,0xff3f3f,sizeof(map));
for (int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
map[a][b]=map[b][a]=min(c,map[a][b]);
}
int s=-1;
for (int i=1;i<n;i++)
{
for (int j=i+1;j<=n;j++)
{
if (map[i][j]<100000)
{
int lp=disk(i,j);
if (lp!=-1)
{
lp+=map[i][j];
if (s==-1)
s=lp;
else
s=min(s,lp);
}
}
}
}
if (s==-1)
printf("It's impossible.\n");
else
printf("%d\n",s);
}
return 0;
}
Description
Nowadays the one-way traffic is introduced all over the world in order to improve driving safety and reduce traffic jams. The government of Dhaka Division decided to keep up with new trends. Formerly all n cities of Dhaka were connected by n two-way roads in the ring, i.e. each city was connected directly to exactly two other cities, and from each city it was possible to get to any other city. Government of Dhaka introduced one-way traffic on all n roads, but it soon became clear that it's impossible to get from some of the cities to some others. Now for each road is known in which direction the traffic is directed at it, and the cost of redirecting the traffic. What is the smallest amount of money the government should spend on the redirecting of roads so that from every city you can get to any other?
Input
Input starts with an integer T (≤ 200), denoting the number of test cases.
Each case starts with a blank line and an integer n (3 ≤ n ≤ 100) denoting the number of cities (and roads). Next n lines contain description of roads. Each road is described by three integers ai, bi, ci (1 ≤ ai, bi ≤ n, ai ≠ bi, 1 ≤ ci ≤ 100) - road is directed from city ai to city bi, redirecting the traffic costsci.
Output
For each case of input you have to print the case number and the smallest amount of money the government should spend on the redirecting of roads so that from every city you can get to any other.
Sample Input
4
3
1 3 1
1 2 1
3 2 1
3
1 3 1
1 2 5
3 2 1
6
1 5 4
5 3 8
2 4 15
1 6 16
2 3 23
4 6 42
4
1 2 9
2 3 8
3 4 7
4 1 5
Sample Output
Case 1: 1
Case 2: 2
Case 3: 39
Case 4: 0
题意:
N个点--N条路----
路是有向路--但是路的方向可以改变---(需要消耗金币)
求最小需要多少钱使N个点强连通
--没有无解的情况---所以N条边让N个点形成了一个环--(只有边的方向不确定---)
这样的话---怎么样才可以强连通呢???
1:顺时针
2:逆时针
想想是为什么-----------
我们可以求出任意一种方向所需要的金钱
另外一个方向所需的金钱个数就是总钱-第一个金钱总和
我们取最小值即可---
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
int a,b,c;
}lu[105];
int fer[105];
int main()
{
int t;scanf("%d",&t);
for (int ca=1;ca<=t;ca++)
{
int n;scanf("%d",&n);
int a,b,c,s=0;
for (int i=0;i<n;i++)
{
scanf("%d%d%d",&lu[i].a,&lu[i].b,&lu[i].c);
s+=lu[i].c;
}
int kp=1;
int s1=0;
while (n--)
{
// printf(" %d 66\n",kp);
for (int i=0;i<=n;i++)
{
// printf("%d %d 0.0.0.\n",lu[i].a,lu[i].b);
if (lu[i].a==kp)
{
kp=lu[i].b;
lu[i]=lu[n];
break;
}
if (lu[i].b==kp)
{
kp=lu[i].a;
s1+=lu[i].c;
lu[i]=lu[n];
break;
}
}
// printf(" %d 99\n",kp);
}
// printf("%d %d 66\n",s,s1);
int ss=min(s1,s-s1);
printf("Case %d: %d\n",ca,ss);
}
return 0;
}
Description
The Vampires and Lykans are fighting each other to death. The war has become so fierce that, none knows who will win. The humans want to know who will survive finally. But humans are afraid of going to the battlefield.
So, they made a plan. They collected the information from the newspapers of Vampires and Lykans. They found the information about all the dual fights. Dual fight means a fight between a Lykan and a Vampire. They know the name of the dual fighters, but don't know which one of them is a Vampire or a Lykan.
So, the humans listed all the rivals. They want to find the maximum possible number of Vampires or Lykans.
Input
Input starts with an integer T (≤ 10), denoting the number of test cases.
Each case contains an integer n (1 ≤ n ≤ 105), denoting the number of dual fights. Each of the next n lines will contain two different integers u v (1 ≤ u, v ≤ 20000) denoting there was a fight between u and v. No rival will be reported more than once.
Output
For each case, print the case number and the maximum possible members of any race.
Sample Input
2
2
1 2
2 3
3
1 2
2 3
4 2
Sample Output
Case 1: 2
Case 2: 3
Hint
Dataset is huge, use faster I/O methods.
Developed and Maintained by
JANE ALAM JAN |
Copyright © 2012
LightOJ, Jane Alam Jan |
并查集+奇偶树----
我们可以将人看成一个一个的点---
对决看成边----
题意就是求:每个联通块的奇偶集合中最大集合的总和了----
用并查集求出每个联通块----
然后求每个联通块求出奇偶集合各自的值----
代码“:
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
int to,next;
}lu[200200];
int head[20010];
int fer[20010];
bool fafe[20010];
struct nn{
int step,to;
}now,qian;
int find(int xx)
{
if (xx==fer[xx])
return xx;
return fer[xx]=find(fer[xx]);
}
int dfs(int xx)
{
int qi=0,ou=0;
queue<nn> que;
now.step=1;
now.to=xx;
que.push(now);
fafe[xx]=false;
while (!que.empty())
{
now=que.front();
que.pop();
if (now.step%2==0)
ou++;
else qi++;
int xx=now.to;
for (int i=head[xx];i!=-1;i=lu[i].next)
{
int y=lu[i].to;
if (fafe[y])
{
qian.step=now.step+1;
qian.to=y;
fafe[y]=false;
que.push(qian);
}
}
}
return max(ou,qi);
}
int main()
{
int t;scanf("%d",&t);
for (int ca=1;ca<=t;ca++)
{
int n;scanf("%d",&n);
for (int i=1;i<=20000;i++)
{
head[i]=-1;
fer[i]=i;
fafe[i]=false;
}
int a,b;
for (int i=0;i<n;i++)
{
scanf("%d%d",&a,&b);
fer[find(a)]=find(b);
lu[2*i].to=b;
lu[2*i].next=head[a];
head[a]=2*i;
lu[2*i+1].to=a;
lu[i*2+1].next=head[b];
head[b]=i*2+1;
fafe[a]=true;
fafe[b]=true;
}
int ans=0;
for (int i=1;i<=20000;i++)
{
if (fafe[i]&&fer[i]==i)
{
ans+=dfs(i);
}
}
printf("Case %d: %d\n",ca,ans);
}
return 0;
}