7-29 AK场

ZOJ 1586

题目的意思是每个人有一个路由器,第二行给出的n的数代表的意思是n个人的路由器需要花多少钱。 
下面给出的方阵的意思:比如第i行第j列的那个数字的意思是:i和j之间建立需要花费的网线费用。 
建边注意一下,边值=i-j的权值+a[i]+a[j](就是i和j的路由器所花的钱)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define up(i,a,n) for(int i=a;i<=n;i++)
const int maxn=5e3+10;
int n,m,arr[maxn],ans;
bool vis[maxn];
struct node
{
	int now,to,cap;
	friend bool operator < (node a,node b)
	{
		return a.cap>b.cap;
	}
	
};
vector<node>g[maxn];
void add(int u,int v,int c)
{   
	g[u].push_back(node{u,v,c+arr[u]+arr[v]});
	g[v].push_back(node{v,u,c+arr[u]+arr[v]});
}
void init()
{   memset(arr,0,sizeof(arr));
	scanf("%d",&n);
	up(i,1,n)scanf("%d",&arr[i]);
	up(i,1,n)
	{
		up(j,1,n)
		{   scanf("%d",&m);
			if(j>i)
			add(i,j,m);
		}
	}
}
int prim()
{
	int sum=0;
	memset(vis,false,sizeof(vis));
	priority_queue<node>q;
	q.push(node{0,1,0});
	while(!q.empty())
	{
		node s=q.top();q.pop();
	    if(vis[s.to])continue;
	    vis[s.to]=true;
	    sum+=s.cap;
	    for(int i=0;i<g[s.to].size();i++)
	    {
	    	if(!vis[g[s.to][i].to])
	    	q.push(g[s.to][i]);
		}
	}
	return sum;
 } 
 int main()
 {   int t;
     scanf("%d",&t);
     while(t--)
     {
    up(i,0,maxn)
    g[i].clear();
 	init();
 	cout<<prim()<<endl;
    }
 }

N皇后的经典问题,回顾一下:

要先打表,然后再输出答案,不然会超时。

主要考虑搜索的回溯问题:就是注意3个标记的重置

1.行

2.列

3.对角线

以行搜索,这样就不用考虑行,因为总是+1,不会重复访问到,那么就剩下3个标记,列,主对角线,副对角线。

所以vis[0][row-i+n]代表第row-i+n条主对角线上是否有人,vis[2][row+i]代表第row+i副对角线上是否有皇后,vis[1][i]代表第i列上是否有,搜索然后回溯就好。配图说明,边缘不算,然后第一个图黄色部分是负的所以要加上n。

#include<stdio.h>
#include<math.h>
#include<string.h>
int vis[3][50],P[15]; 
int n,sum;
void DFS(int row)
{
int i;
if(row==n+1)
{
	sum++;
	return ;
}
for(i=1;i<=n;i++)
{
	if(vis[0][row-i+n]==0&&vis[1][i]==0&&vis[2][row+i]==0)
	{ 
	vis[0][row-i+n]=vis[1][i]=vis[2][row+i]=1;
	DFS(row+1);
	vis[0][row-i+n]=vis[1][i]=vis[2][row+i]=0;
    }
    } 
}
int main()
{  for(n=1;n<=10;n++)
{
	memset(vis,0,sizeof(vis));
	sum=0;
	DFS(1);
	P[n]=sum;
}
while(scanf("%d",&n)&&n)
{
	printf("%d\n",P[n]);
}
	return 0;
 } 

LIS原题,就是求最长上升子序列

有个什么鬼东西的定理(之前看到过

就是

一个序列的下降子序列个数=最长上升子序列的长度

这题也可以DP写。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define up(i,a,n) for(int i=a;i<=n;i++)
const int maxn=1e6+10;
int arr[maxn];
int f[maxn];
int main()
{
   int n;
   while(~scanf("%d",&n))
   {
   	memset(f,0,sizeof(f));
   up(i,1,n)scanf("%d",&arr[i]);
   int len=0;
   up(i,1,n)
   {
   	if(arr[i]>f[len])f[++len]=arr[i];
   	else
   	{
   		int pos=lower_bound(f+1,f+len+1,arr[i])-f;
   		f[pos]=arr[i];
	}
   }
   printf("%d\n",len);
   }
}

D题:

给出一个圆,半径为 rr,其周围有 n个完全相同的圆将其包围,这 n 个圆分别和中心圆互相紧贴,且这 n 个圆构成一个环,环上任意两个相邻的圆也都是紧贴的。要求你求出这 n 个圆的半径 R

题解:数学题,算一下。什么余弦定理正弦定理乱搞

解法很多

百度了一份比较好的:https://www.cnblogs.com/RB26DETT/p/10763323.html

#include<stdio.h>
#include<math.h>
const double PI=3.14159265358979323846;
int main()
{
	int x,r;
	scanf("%d %d",&x,&r);
	double R,s=cos(2*PI/x),d=sqrt(2*(1-s));
    R=r*d/(2-d);
		printf("%.7f",R);
}

E题:

从1跑一遍最短路,从n跑一遍,然后枚举每一条边,每条边上有两个顶点,判断1-左顶点和n到右顶点的值,记录下来就是答案

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<string>
//#include<regex>
#include<cstdio>
using namespace std;
#define ll long long 
#define inf 0x3f3f3f3f
const int N=5e3+10;
const int maxn=5e5+10;
struct node
{
	int to,cap,next;
	node(){}
	node(int to,int cap):to(to),cap(cap){}
	bool operator < (const node &a)const
	{
		return  cap>a.cap;
	}
}g[maxn];
int head[maxn];
int dis[N],dis1[N],dis2[N];
bool vis[N];
int n,m,cnt;
void add(int u,int v,int cap)
{
	g[cnt].to=v;
	g[cnt].cap=cap;
	g[cnt].next=head[u];
	head[u]=cnt++;
}
priority_queue<node>q;
void dijkstra(int s)
{ 
	memset(vis,false,sizeof(vis));
	memset(dis,inf,sizeof(dis));
	dis[s]=0;
	while(!q.empty())q.pop();
	q.push(node(s,0));
	while(!q.empty())
	{
		node s=q.top();q.pop();
		if(vis[s.to])continue;
		vis[s.to]=true;
		for(int i=head[s.to];i!=-1;i=g[i].next)
		{   //cout<<i<<endl;
			if(!vis[g[i].to]&&dis[g[i].to]>dis[s.to]+g[i].cap)
			{
			dis[g[i].to]=dis[s.to]+g[i].cap;
			q.push(node(g[i].to,dis[g[i].to]));
			}
		}
	}

}
int main()
{  
	while(~scanf("%d %d",&n,&m))
	{
	cnt=0;
	memset(head,-1,sizeof(head));
	for(int i=0;i<m;i++)
	{
		int u,v,w;
		scanf("%d %d %d",&u,&v,&w);
		add(u,v,w);
		add(v,u,w);
	}
	dijkstra(1);
	for(int i=1;i<=n;i++)dis1[i]=dis[i];
	dijkstra(n);
	for(int i=1;i<=n;i++)dis2[i]=dis[i];
	int ans=inf;
	for(int i=1;i<=n;i++)
	{
		for(int j=head[i];j!=-1;j=g[j].next)
		{
			int temp=g[j].cap+dis1[i]+dis2[g[j].to];
			if(temp>dis1[n]&&temp<ans)ans=temp;
		}
	}
	printf("%d\n",ans);
    }
    return 0;
}

F题:

二分或者直接用STL中的upper_bound。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e9+10;
int main()
{
	int n,m;
	scanf("%d %d",&n,&m);
	int arr[200002];
	for(int i=0;i<n;i++)
	{
		scanf("%d",&arr[i]);
	}
	sort(arr,arr+n);
	for(int i=0;i<m;i++)
	{
		int q;
		scanf("%d",&q);
		int left=0;
		int right=n;
		int mid;
		while(right>left)
		{
			mid=(left+right)/2;
			if(arr[mid]<q+1)left=mid+1;
			else right=mid;
		}
		printf("%d ",left);
	
	}
	return 0;
}

G题:

直接看代码

#include<stdio.h>
int main()
{
	long long int n;
	scanf("%lld",&n);
	if(n%2==1)printf("-%lld",n/2+1);
	else printf("%lld",n/2);
	return 0;
}
发布了67 篇原创文章 · 获赞 4 · 访问量 4802

猜你喜欢

转载自blog.csdn.net/weixin_44203780/article/details/97617127