Oil Deposits
题目大意
给定一个矩形区域,询问有多少个全为‘@’的连通块。
a与b属于同一连通块当且仅当至少满足下列的一个条件:
1,a与b相邻。(当a在以b为中心的8个位置中的一个时,认为a与b相邻)
2,a的相邻点与b或b的相邻点属于同一连通块。
3,b的相邻点与a或a的相邻点属于同一连通块。
数据输入
输入可能有多个矩形区域(即可能有多组测试)。
每个矩形区域的起始行包含m和n,表示行和列的数量,1<=n,m<=100。
当m =0时,输入结束。
接下来是n行,每行m个字符。
每个字符对应一个小方格,要么是’*’,代表禁止区域,要么是’@’。
数据输出
对于每一个矩形区域,输出’@'的连通块数量。
样例
输入
1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5
****@
*@@*@
*@**@
@@@*@
@@**@
0 0
输出
0
1
2
2
算法思路
深度优先搜索加标记
八个方向分别搜索,然后读取的时候需要按行读取,外围加上一圈‘*’不用判断越界问题
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
char c[105][105];
int f[105][105];
int tot=0;
void dfs(int x,int y,int flag){
f[x][y]=flag;
if(c[x+1][y]=='@'&&f[x+1][y]==0){
dfs(x+1,y,flag);//往下走
}
if(c[x][y+1]=='@'&&f[x][y+1]==0){
dfs(x,y+1,flag);//往右走
}
if(c[x-1][y]=='@'&&f[x-1][y]==0){
dfs(x-1,y,flag);//往上走
}
if(c[x][y-1]=='@'&&f[x][y-1]==0){
dfs(x,y-1,flag);//往左走
}
if(c[x+1][y+1]=='@'&&f[x+1][y+1]==0){
dfs(x+1,y+1,flag);//往右下走
}
if(c[x+1][y-1]=='@'&&f[x+1][y-1]==0){
dfs(x+1,y-1,flag);//往左下走
}
if(c[x-1][y-1]=='@'&&f[x-1][y-1]==0){
dfs(x-1,y-1,flag);//往左上走
}
if(c[x-1][y+1]=='@'&&f[x-1][y+1]==0){
dfs(x-1,y+1,flag);//往右上走
}
}
int main(){
while(1){
scanf("%d%d",&n,&m);
if(n==0&&m==0){
break;
}
string s;
for(int i=1;i<=n;i++){
cin>>s;
for(int j=1;j<=m;j++){
c[i][j]=s[j-1];
c[0][j]='*';
c[n+1][j]='*';
}
c[i][0]='*';
c[i][m+1]='*';
}
c[0][0]=c[n+1][m+1]=c[0][m+1]=c[n+1][0]='*';
tot=0;
for(int i=0;i<=n+1;i++){
for(int j=0;j<=m+1;j++){
f[i][j]=0;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(c[i][j]=='@'&&f[i][j]==0){
tot++;
dfs(i,j,tot);
}
}
}
cout<<tot<<endl;
}
return 0;
}
蜘蛛牌
题目介绍
蜘蛛牌是windows xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么这些牌也跟着一起移动,游戏的目的是将所有的牌按同一花色从小到大排好,为了简单起见,我们的游戏只有同一花色的10张牌,从A到10,且随机的在一行上展开,编号从1到10,把第i号上的牌移到第j号牌上,移动距离为abs(i-j),现在你要做的是求出完成游戏的最小移动距离。
数据输入
第一个输入数据是T,表示数据的组数。
每组数据有一行,10个输入数据,数据的范围是[1,10],分别表示A到10,我们保证每组数据都是合法的。
数据输出
对应每组数据输出最小移动距离。
样例
输入
1
1 2 3 4 5 6 7 8 9 10
输出
9
算法思路
深搜加剪枝
深搜枚举所有情况,找到最小的那种
通过剪枝操作减少搜索次数,提高运算效率
存储每张牌的位置然后按照牌的大小进行深搜
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int t;
int a[15];
bool f[15];
int ans;
int Abs(int x){
return x>0?x:-x;
}
void dfs(int num,int sum){
if(sum>=ans)return ;
if(num==9){
ans=sum;
return ;
}
for(int i=1;i<10;i++){
if (f[i]==0)
{
f[i]=1;
for(int j=i+1;j<=10;j++){
if (f[j]==0)
{
dfs(num+1,sum+Abs(a[i]-a[j]));
break;
}
}
f[i]=0;
}
}
}
int main(){
scanf("%d",&t);
while(t--){
for(int i=1;i<=10;i++){
int x;
scanf("%d",x);
a[x]=i;
}
memset(f,0,sizeof(f));
ans=1e5+7;
dfs(0,0);
cout<<ans<<endl;
}
return 0;
}
N皇后 八皇后
题目介绍
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
数据输入
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
数据输出
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
样例
输入
1
8
5
0
输出
1
92
10
算法思路
深搜+剪枝+打表+找规律
问题分析
1.一行只能放一个皇后,所以我们一旦确定此处可以放皇后,那么该行就只能放一个皇后,下面的就不要再搜了。
2.每一列只能放一个皇后,所以我们下次搜索就不要再搜已经放过的皇后了。
3.斜的45°线也只能放一个。
重点是45°的情况不好判断
左上到右下 | 左下到右上 |
---|---|
0 1 2 3 4 | 0 1 2 3 4 |
-1 0 1 2 3 | 1 2 3 4 5 |
-2 -1 0 1 2 | 2 3 4 5 6 |
-3 -2 -1 0 1 | 3 4 5 6 7 |
-4 -3 -2 -1 0 | 4 5 6 7 8 |
列-行相等 | 行+列相等 |
因为N<=10所以我们只需要先跑出所有情况然后 直接输入一次判断一次判断就好了
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int n,sum;
int f[3][50],ans[15];
void dfs(int now,int N){
if(now==N+1){
sum++;
return ;
}
for(int i=1;i<=N;i++){
if(f[0][now-i+N]==0&&f[1][i]==0&&f[2][now+i]==0){//f[0]判断下对角线,f[1]判断列,f[2]判断上对角线
f[0][now-i+N]=1;
f[1][i]=1;
f[2][now+i]=1;
dfs(now+1,N);
f[0][now-i+N]=0;
f[1][i]=0;
f[2][now+i]=0;
}
}
}
int main(){
for(int i=1;i<=10;i++){
memset(f,0,sizeof(f));
sum=0;
dfs(1,i);
ans[i]=sum;
}
while(cin>>n&&n){
cout<<ans[n]<<endl;
}
return 0;
}
Agri-Net
题目大意
有n个农场,已知这n个农场都互相相通,有一定的距离,现在每个农场需要装光纤,问怎么安装光纤能将所有农场都连通起来,并且要使光纤距离最小,输出安装光纤的总距离
任意两个村庄之间的距离小于 100,000.
数据输入
输入包含多组数据。对于每组数据, 第一行包含一个整数N表示农场的数量 (3 <= N <= 100). 接下来是一个
N
∗
N
N*N
N∗N
的邻接矩阵,表示各个村庄之间的距离 . 当然,对角线将是0,因为从农场到农场的距离对于这个问题并不有趣。
数据输出
对于每种情况,请输出一个整数表示长度,该长度是连接整个农场集合所需的最小光纤长度的总和。
样例
输入
4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0
输出
28
题目思路
最小生成树 克鲁斯卡尔和prim
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int n;
struct edge{
int u,v,w;
};
vector<edge>e;
int fa[105];
int ans=0;
bool cmp(edge a,edge b){
return a.w<b.w;
}
int find(int x){
if(fa[x]==x)
return x;
else
return fa[x]=find(fa[x]);
}
void uunion(int x,int y){
x=find(x);
y=find(y);
if(x==y){
return ;
}
else{
fa[y]=x;
}
}
int main(){
while(scanf("%d",&n)!=EOF){
int tot=0;
e.clear();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
edge k;
cin>>k.w;
if(i!=j){
k.u=i;
k.v=j;
e.push_back(k);
}
}
}
sort(e.begin(),e.end(),cmp);
for(int i=0;i<=n;i++){
fa[i]=i;
}
int cnt=0;
ans=0;
for(int i=0;i<e.size();i++){
if(find(e[i].u)!=find(e[i].v)){
uunion(e[i].u,e[i].v);
ans+=e[i].w;
cnt++;
}
}
if(cnt==n-1)
printf("%d\n",ans);
else
printf("-1\n");
}
return 0;
}
Jungle Roads
题目大意
小镇的街道非常杂乱,使得道路的维护费用十分昂贵。 所以我们不得不拆除某些道路。 现在已知重建前,各个店铺之间道路的维护费用。 作为小镇的管理者,你想知道将所有店铺连接起来,需要花费最少的金额。
数据输入
(最多100次询问)对于每次询问: 第一行给出店铺数量n; 接下来第二行到第n+1行, 给出当前店铺名称a ,与之直接相连的店铺的道路数k ,之后k组数据表示 与a相连的店铺名称和他们之间的道路维护费用 (多组数据输入,当店铺数量为0时,输入结束) 1 < n < 27, 0 <= k <= 15
数据输出
重建后需要花费的最少金额 上一个题我们是直接得到了一个完整的邻接矩阵,也就是说 我们可以通过邻接矩阵直接获取两点之间的边权
给你一个点 然后 这个点到另外的点的距离 也就是说 这是给你了一个图需要你自己去存储
样例
输入
9
A 2 B 12 I 25
B 3 C 10 H 40 I 8
C 2 D 18 G 55
D 1 E 44
E 2 F 60 G 38
F 0
G 1 H 35
H 1 I 35
3
A 2 B 10 C 40
B 1 C 20
0
输出
216
30
算法思路
邻接表+克鲁斯卡尔最小生成树
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int n;
int fa[30];
int ans=0;
struct edge{
int u,v,w;
};
edge e[900];
int cnt=0;
void add_edge(int u,int v,int w){
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
}
bool cmp(edge a,edge b){
return a.w<b.w;
}
int find(int x){
if(fa[x]==x)return x;
else return fa[x]=find(fa[x]);
}
void uunion(int x,int y){
x=find(x);
y=find(y);
if(x==y){
return ;
}
else{
fa[y]=x;
}
}
int main(){
while(cin>>n&&n){
for(int i=1;i<=26;i++){
fa[i]=i;
}
cnt=0;
for(int i=1;i<n;i++){
char x;
int s;
cin>>x>>s;
for(int j=1;j<=s;j++){
char v;
int w;
cin>>v>>w;
add_edge(x-'A'+1,v-'A'+1,w);
}
}
sort(e+1,e+1+cnt,cmp);
ans=0;
for(int i=1;i<=cnt;i++){
int u=e[i].u;
int v=e[i].v;
int w=e[i].w;
if(find(fa[u])!=find(fa[v])){
uunion(u,v);
ans+=w;
}
}
cout<<ans<<endl;
}
return 0;
}
Truck History
题目大意
编写程序输出最高质量的火车推导计划。火车推倒计划质量的求解公式中的分子为1,分母为t0,td的距离总和。
t0,td的距离就是两个输入字符串的字母不同位置的个数。想要推导计划的质量最高就是使分母最小。即t0,td的距离总和最小。
数据输入
多组输入,以0结束。 保证N不超过2000。
数据输出
每组输出"The highest possible quality is 1/Q."。
样例
输入
4
aaaaaaa
baaaaaa
abaaaaa
aabaaaa
0
输出
The highest possible quality is 1/3.
算法思路
字符串比对+克鲁斯卡尔最小生成树+常数优化 KMP 字符串比对算法
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
const int MAXN=2000+2;
struct edge{
int u,v,w;
};
edge e[MAXN*MAXN];
string s[MAXN];
int cnt=0;
int ans=0;
int fa[MAXN];
int n;
bool cmp(edge a,edge b){
return a.w<b.w;
}
void init(){
cnt=0;
ans=0;
for(int i=1;i<=n;i++){
fa[i]=i;
}
}
void make_edge(){
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int sum=0;
int len=s[i].length();
for(int l=0;l<len;l++){
if(s[i][l]!=s[j][l])
sum++;
}
cnt++;
e[cnt].u=i;
e[cnt].v=j;
e[cnt].w=sum;
}
}
}
inline int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void kru(){
for(int i=1;i<=cnt;i++){
int x=find(e[i].u);
int y=find(e[i].v);
int w=e[i].w;
if(x!=y){
fa[y]=x;
ans+=w;
}
}
printf("The highest possible quality is 1/%d.\n",ans);
}
int main(){
while(~scanf("%d",&n)&&n){
for(int i=1;i<=n;i++){
std::cin>>s[i];
}
init();
make_edge();
sort(e+1,e+1+cnt,cmp);
kru();
}
return 0;
}
Connections between cities
题目大意
一场突如其来的爆炸,摧毁了许多村子之间的通道。爆炸后,我们得知有些村子之间不能直接或间接相通了,但是也是不存在圈的,就是说不存在这样一条路,从某个村子出发通过一些村子又回到了最初的村子。
我们希望你们写一个程序帮我们确定两个村子之间的最短路径,或者确定他们不能相通。
数据输入
输入由多个问题实例组成。对于每个实例,第一行包含三个整数n、m和c, 2<=n<=10000, 0<=m<10000, 1<=c<=1000000。n代表村子编号的数量从1到n。m行,每一行有三个整数i, j和k,代表一个村子i和j之间的道路,与长度k。c代表询问的次数,接下来每行两个整数i, j,表示我们想知道村子i和j之间是否相通,相通的话最短路径是多少。
数据输出
对于每个问题实例,每个查询对应一行。如果两城市之间没有路径,输出“Not connected”,否则输出两城市之间最短路径的长度
样例
输入
5 3 2
1 3 2
2 4 3
5 2 3
1 4
4 5
输出
Not connected
6
算法思路
建树+倍增+LCA+树节点路径长度 求 最小生成树 LCA 倍增LCA 树节点路径长度 树的直径
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 1e5+5;
const int ins = 20;
int f[maxn][ins];
int pre[maxn];
int dis[maxn];
int dep[maxn];
struct node
{
int v,next,w;
}e[maxn<<1];
int head[maxn],cnt;
int n,m,q;
void add(int u,int v,int w)
{
e[++cnt].v = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt;
}
void init()
{
cnt = 0;
for(int i = 0; i <= n; i++)
pre[i] = i;
memset(head , -1, sizeof(head));
memset(f, 0, sizeof(f));
memset(dis, 0, sizeof(dis));
memset(dep, 0, sizeof(dep));
}
int findd(int x)
{
return x == pre[x] ? x : pre[x] = findd(pre[x]);
}
void merage(int a,int b)
{
a = findd(a);
b = findd(b);
if(a != b)
pre[a] = b;
}
void dfs(int x,int p,int d)
{
f[x][0] = p;
dep[x] = dep[p] + 1;
dis[x] = d;
for(int i=1;i<=19;i++)
{
f[x][i] = f[f[x][i - 1]][i - 1];
}
for(int i=head[x];~i;i=e[i].next)
{
int v = e[i].v;
if(v != p)
{
dfs(v, x, dis[x] + e[i].w);
}
}
}
int lca(int a,int b)
{
if(dep[a] > dep[b])
swap(a,b);
for(int i=19;i>=0;i--)
{
if(dep[f[b][i]] >= dep[a])
b = f[b][i];
}
if(a == b)
return a;
for(int i=19;i>=0;i--)
{
if(f[a][i] != f[b][i])
{
a = f[a][i];
b = f[b][i];
}
}
return f[a][0];
}
int main()
{
while(scanf("%d%d%d",&n,&m,&q) == 3)
{
int u,v,w;
init();
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
merage(u,v);
}
for(int i=1;i<=n;i++)
{
if(pre[i] == i)
dfs(i, 0, 0);
}
while(q--)
{
scanf("%d%d",&u,&v);
if(findd(u) == findd(v))
printf("%d\n",dis[u] + dis[v] - 2 * dis[lca(u, v)]);
else
printf("Not connected\n");
}
}
return 0;
}