周测题目解析

文章目录

  • C - hollowknight
  • D - 格林团长的烦恼
  • E - ksm走迷宫
  • F - 果果玩数独 (经典dfs)
  • G - 探月与魔王
  • H - 魔王的宝藏
  • J - 纯粹容器

C - hollowknight

题意
在空洞骑士中,小骑士封印了最终boss辐光。圣巢又一次迎来了和平。但是经历了辐光的感染后,圣巢的很多设施都报废掉了。小姐姐大黄蜂作为圣巢之子,担负着重建圣巢的使命。其中一个任务,就是修复一些连接各个村庄的坍塌的双向鹿角虫通道。小姐姐希望用最少的人力(即修复最短的通道距离),使圣巢的各个村庄之间再次互相连通(直接连通或者间接连通)。

我们现在知道有一些村庄的鹿角虫通道依旧完好,请问你能帮助大黄蜂小姐姐来计算出最少的花费吗?
Input
第一行有一个整数N (3 <= N <= 100),表示村庄的个数。之后是N行数据,第i行有N个整数,该行的第j个整数表示村庄i与j之间的距离。距离的长度在 [1, 1000]范围内。

之后是一个整数Q(0 <= Q <= N * (N + 1) / 2). 之后是Q行,每一行包括两个整数a,b (1 <= a < b <= N)表示村庄a与村庄b仍有一个完好的鹿角虫通道
Output
你需要输出一个整数,来表示连通各个村庄的最少花费
分析:求最小生成树,完好的路径花费为0

#include
#include

using namespace std;
struct edge
{
	int u,v,w;
};
struct edge e[20001];
int n,m;
int f[5001]={0},sum=0;
int cmp(edge x,edge y)
{
	return x.w<y.w;
}
int getf(int v)
{
	if(f[v]==v)
		return v;
	else
	{
		f[v]=getf(f[v]);
		return f[v];
	}
}
int merge(int v,int u)
{
	int t1,t2;
	t1=getf(v);
	t2=getf(u);
	if(t1!=t2)
	{
		f[t2]=t1;
		return 1;
	}			
	return 0;
}

int main()
{	
	int count=0;
	int flag=0;
	int i;
	scanf("%d",&n);
	int index;
	int cnt=0; 
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	{
		scanf("%d",&index);
		e[++cnt].u=i,e[cnt].v=j,e[cnt].w=index;
	}
	for(i=1;i<=n;i++)
		f[i]=i;
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		e[++cnt].u=a,e[cnt].v=b,e[cnt].w=0;
	}
	sort(e+1,e+1+cnt,cmp);	
	for(i=1;i<=cnt;i++)
	{
		if(merge(e[i].u,e[i].v))//寻找未连通的边,并联通 
		{
			count++;
			sum+=e[i].w;
		}
		if(count==n-1)//得到n-1边则成功 
		{
			flag=1;
			break;
		}
	}
	
	printf("%d",sum);
   
	return 0;

}

D - 格林团长的烦恼

题意
格林剧团发工资的时候又到辣,格林剧团来到了圣巢,他们入乡随俗,将工资用圣巢的货币–吉欧来结算。格林团长决定每个人的最低工资是888吉欧,同时有些工人希望自己的工资要比其他某个人的高。格林团长希望在尽可能的少发工资的同时满足其他所有人的需求。请你帮帮格林团长吧,格林团长会邀请你与其在剧团内共舞一场猩红仪式。
Input
题目包含多组输入 第一行输入两个整数n,m,分别表示工人的数量与需求的个数。 接下来m行,每一行都包含两个整数a和b,表示a的工资必须比b的工资高
Output
对于每一组输入,输出格林团长最少花费的吉欧数量。如果格林团长不能满足所有人的需求,输出-1.
分析:拓扑排序,找到每个人所在的等级

#include
#include
#include
#include

#include
#define intn long long
#define _0for(i, a) for(int i = 0; i < (a); ++i)
#define _1for(i, a) for(int i = 1; i <=(a); ++i)
using namespace std;
int main()
{
	int n, m;//节点数 边数
	vector<vector<int>> G; //图
	vector<int> in;//入度数

	while (cin >> n >> m)
	{
		if (n == 0 && m == 0) { break; }
		G = vector<vector<int>>(n + 1); //有n个点
		in = vector<int>(n + 1);
		for (int i = 1, a, b; i <= m; i++)
		{
			cin >> b >> a; //生动形象 a>>b a指向b
			G[a].push_back(b); //添加该点指向了什么点
			in[b]++; //该点入度数+1
		}
		queue<pair<int,int>> q; pair<int,int>t;
		int ans=0;
	 	int cnt=0;
		for (int i = 1; i <= n; i++)
			if (in[i] == 0) { q.push(make_pair(i,888)); } //如果入度数为0则添加
		while (!q.empty()) //bfs遍历
		{
			t = q.front(); q.pop();
			cnt++;
			ans+=t.second;
			for (size_t i = 0; i < G[t.first].size(); i++) //寻找除去该点后还有那些入度数为0的点
			{
				in[G[t.first][i]]--;
				if (in[G[t.first][i]] == 0) q.push(make_pair(G[t.first][i],t.second+1));
			}
		}
		if(cnt!=n)//如果形成了环就永远不会入度为0,得不到n个人的等级
		printf("-1\n");
		else
		{
			printf("%d\n",ans);
		}
	}
}

E - ksm走迷宫

dfs或者bfs

#include
#include
#define intn long long
#define _0for(i, a) for(int i = 0; i < (a); ++i)
#define _1for(i, a) for(int i = 1; i <=(a); ++i)
using namespace std;
int dx[5]={0,1,-1,0,0};
int dy[5]={0,0,0,1,-1};

int book[10][10];
int a[10][10];
int mbu=99999999;
int bx[1000],by[1000];
int flag=0;
int ansx[100],ansy[100];
int djs(int x,int y,int s)
{
	if(a[x][y]==1)
	return 1;
	if(x<1||y<1||x>5||y>5)
	return 1;
	if(book[x][y])return 1;
	if(s>mbu)
	return 1;
	bx[s]=x,by[s]=y;
	if(x==5&&y==5)
	{
		if(mbu>s)
		{
			mbu=s;
			for(int i=1;i<=s;i++)
			{
				ansx[i]=bx[i];
				ansy[i]=by[i];
			}
		}	
		return 1;	
	}
	for(int i=1;i<=4;i++)
	{
		book[x][y]=1; 
		djs(x+dx[i],y+dy[i],s+1);
		book[x][y]=0;
	}
}
int main()
{
	for(int i=1;i<=5;i++)
	for(int j=1;j<=5;j++)
	{
		scanf("%d",&a[i][j]);
	}
	djs(1,1,1);
	for(int i=1;i<=mbu;i++)
	{
		printf("(%d, %d)\n",ansx[i]-1,ansy[i]-1);
	}
	return 0;
}



F - 果果玩数独 (经典dfs)

#include 
using namespace std;
bool sign = false;
int num[9][9];
void Input();
void Output();
bool Check(int n, int key);
int DFS(int n);
int main()
{
    cout << "请输入一个9*9的数独矩阵,空位以0表示:" << endl;
    Input();
    DFS(0);
    Output();
    system("pause");
}
void Input()
{
    char temp[9][9];
    for (int i = 0; i < 9; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            cin >> temp[i][j];
            num[i][j] = temp[i][j] - '0';
        }
    }
}
void Output()
{
    cout << endl;
    for (int i = 0; i < 9; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            cout << num[i][j] << " ";
            if (j % 3 == 2)
            {
                cout << "   ";
            }
        }
        cout << endl;
        if (i % 3 == 2)
        {
            cout << endl;
        }
    }
}
bool Check(int n, int key)
{
    for (int i = 0; i < 9; i++)
    {
        int j = n / 9;
        if (num[j][i] == key) return false;
    }
    for (int i = 0; i < 9; i++)
    {
        int j = n % 9;
        if (num[i][j] == key) return false;
    }
    int x = n / 9 / 3 * 3;//注意理解
    /* y为n所在的小九宫格左顶点横坐标 */
    int y = n % 9 / 3 * 3;
    /* 判断n所在的小九宫格是否合法 */
    for (int i = x; i < x + 3; i++)
    {
        for (int j = y; j < y + 3; j++)
        {
            if (num[i][j] == key) return false;
        }
    }
    /* 全部合法,返回正确 */
    return true;
}
/* 深搜构造数独*/
int DFS(int n)
{
    /* 所有的都符合,退出递归 */
    if (n > 80)
    {
        sign = true;
        return 0;
    }
    /* 当前位不为空时跳过 */
    if (num[n/9][n%9] != 0)//n与行和列的关系
    {
        DFS(n+1);
    }
    else
    {
        /* 否则对当前位进行枚举测试 */
        for (int i = 1; i <= 9; i++)
        {
            /* 满足条件时填入数字 */
            if (Check(n, i) == true)
            {
                num[n/9][n%9] = i;
                /* 继续搜索 */
                DFS(n+1);
                /* 返回时如果构造成功,则直接退出 */
                if (sign == true) return 0;
                /* 如果构造不成功,还原当前位 */
                num[n/9][n%9] = 0;
            }
        }
    }
}

G - 探月与魔王

题意给你一个整数n。找出三个不同的整数a、b、c,使得2≤a、b、c和a⋅b⋅c=n,或者说这是不可能的。
如果有几个答案,你可以打印任何答案。

你必须回答独立的测试用例。

Input
输入的第一行包含一个整数t(1≤t≤100)-测试用例的数量。
接下来的n行描述测试用例。第i个测试用例作为一个整数n(2≤n≤10^9)在新的一行上给出。

Output
对于每个测试用例,在上面打印答案。如果无法将某些不同整数a、b、c的n表示为a⋅b⋅c,使2≤a、b、c,则打印“NO”。
否则,打印“YES”和任何可能的此类表示。
分析:枚举a,b

#include
#include
#include
#include
#include
#define intn long long
#define _0for(i, a) for(int i = 0; i < (a); ++i)
#define _1for(i, a) for(int i = 1; i <=(a); ++i)
using namespace std;

main(void)
{
	int t,n;
	cin>>t;
	for(int p=1;p<=t;p++)
	{
		cin>>n;
		int flag=0;
		for(int a=2;a*a*a<=n;a++)
		{
			if(n%a==0)
			{
				int bc=n/a;
				for(int b=a+1;b*b<bc;b++)
				{
					if(bc%b==0)
					{
						if(flag==0)printf("YES\n");
						flag++;
						printf("%d %d %d\n",a,b,bc/b);
						break;
					}
				}
				if(flag)break;
			}
		}
		if(flag==0)
		printf("NO\n");
	}
}



H - 魔王的宝藏

题意
LCM的指两个数的最小公倍数
现在XHK手上有一个X
请你找到这样的一对数(a,b),使得LCM(a,b)=x,并且max(a,b)要尽可能的小
Input
输入只包含一个数X(X<=1e12)
Output
输出包含两个数字a,b
x等于两个质数的积

J - 纯粹容器

题意
每个在圣巢的容器骑士都会希望成为最纯粹的容器。在 N (1 <= N <= 10,000) 个骑士里, 给定M (1 <= M <= 50,000) 个有序数对 (A, B)表示A认为B是纯粹的. 这种关系具有传递性, 如果A认为B是纯粹的,B认为C是纯粹的,那么A就认为C是纯粹的。被其他所有骑士都认定为纯粹的骑士,就将成为纯粹容器。
Input
第一行给定两个整数N和M 接下来的M行,每行两个整数A和B,表示A认为B是纯粹的。
Output
输出有多少个纯粹容器。
分析:tarjan算法缩点,然后统计出度,如果出度为0的点(最后到达)有1个,那么他的数量就纯粹容器的数量,如果多于一个就没有纯粹容器

#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=10020;
vector<int>g[maxn];

int dfn[maxn],low[maxn],ins[maxn],bl[maxn],num,numb,nums[maxn];
int od[maxn];
stack<int>st;
void tarjan(int x)
{
	dfn[x]=low[x]=++num;
	ins[x]=1;
	st.push(x);

	for(int i=0;i<g[x].size();i++)
	{
		int q=g[x][i];
		if(dfn[q]==0)
		{
			tarjan(q);
			low[x]=min(low[q],low[x]);
		}
		else if(ins[q]==1)
		{
			low[x]=min(low[x],dfn[q]);
		}
	}
	if(dfn[x]==low[x])
	{
		numb++;
		int p;
		do
		{
			p=st.top();
			st.pop();
			bl[p]=numb;
			nums[numb]++;
			ins[p]=0;
		}
		while(x!=p);
	}
}
int main()
{
	int n,m,i,x,y,j,v;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;++i){
        scanf("%d%d",&x,&y);
        g[x].push_back(y);
    }
    memset(dfn,0,sizeof(dfn));
    for(i=1;i<=n;++i)if(!dfn[i])tarjan(i);
    for(i=1;i<=n;++i)
    for(j=0;j<g[i].size();++j){
        v=g[i][j];
        if(bl[i]!=bl[v])od[bl[i]]++;
    }
    x=0;
    for(i=1;i<=numb;++i)
    if(!od[i]){
        if(x>0){
            printf("0");
            return 0;
        }
        x=nums[i];
    }
    printf("%d",x);
    return 0;
}

你可能感兴趣的:(acm)