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;
}