即hdu题库中的4706-4715
题意:用a~z构造一个反"N"型图形,z后面接a;
思路:直接cout构造就可以了,大水题,不过可以写写循环练习代码能力
代码:
#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000;
char mir[] = "abcdefghijklmnopqrstuvwxyz";
int cnt=0;
char out[11][11];
void mk(int n)
{
for(int i = 0 ; i < 10 ; i++)
fill(out[i],out[i]+10,' ');
for(int i = 0 ; i < n ; i++)
{
out[i][0] = mir[(cnt+i)%26];
out[i][n-1] = mir[(cnt+i+2*n-2)%26];
out[i][n-1-i] = mir[(cnt-i+2*n-2)%26];
out[i][n] = '\0';
}
cnt+=3*n-2;
for(int i = 0 ; i < n ; i++)
cout << out[i] << endl;
}
int main()
{
for(int i = 3 ; i<=10 ;i++)
mk(i);
return 0;
}
题意:0点有个探测器,能探测到距0点D单位以内的仓鼠,输入x,y表示x在y旁边,也就是说x与y相差一个单位,每一个点可达到0点,问仓鼠有可能在哪几个地方,输出个数
思路:其实就是构造一颗树,以0为根节点,每条边权都为1,求子节点到根节点权值超过D的点的个数,一个简单的简化拓扑排序
代码:
#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000;
int in[100010];
int main()
{
int t;
cin >> t;
while(t--)
{
memset(in,0,sizeof(in));
int n,d;
cin >> n >> d;
for(int i=1 ; i < n ; i++)
{
int x,y;
scanf("%d%d",&x,&y);
in[y] = in[x]+1;
}
int cnt=0;
for(int i=0 ; i < n ; i++)
if(in[i] > d)
cnt++;
cout << cnt << endl;
}
return 0;
}
题意:每一圈(条纹走向相等的为一圈)可以顺逆时针旋转,求的是旋转后每一圈四个角的和+最中间数的和(即整体矩形的两条对角线元素的和,中间那个算一次),以及最小旋转次数
思路:已知的是:(仅考虑在某一圈)如果两个数能够在旋转后居于对角角落位置,则有(x1,y1)+(x2,y2)=(n+1,n+1) ; 如果两个数能够在旋转后居于非对角角落位置(在矩形的同一条边上) , 则有x1=y2 , x2+y1 = n+1; 这样,我们只要枚举一条边的一个点就可以了
特别注意:当遇到maxc相等的时候,别忘了更新最小旋转次数!!
代码:
#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000;
int cir[20][20];
int main()
{
int n;
while(cin >> n && n)
{
for(int i = 1 ; i<= n ; i++)
for(int j = 1 ; j <= n ; j++)
cin >> cir[i][j];
int res1=0,res2=0;
for(int i = 1 ; i <= n/2;i++)
{
int maxc = -1000000,pos=0;
for(int j = i ; j <= n-i ; j++)
{
int res = cir[i][j] +cir[j][n-i+1] + cir[n+1-j][i] + cir[n+1-i][n+1-j];
if(maxc < res)
{
maxc = res;
pos = min(j-i,n-i-j+1);
}
else if(maxc == res)
pos = min(pos,min(j-i,n-i-j+1));
}
res1 += maxc;
res2 += pos;
}
cout << res1+cir[n/2+1][n/2+1] << ' ' << res2 << endl;
}
return 0;
}
题意:给一组点,求能构成的三角形的最小面积
思路:才100个点,三个for循环直接暴力枚举,这里麻烦的是三角形面积,用海伦公式太不靠谱,介绍用叉乘计算:
三角形面积计算法 : 给定三个顶点 , 两两相减得到两条边向量A,B ; 则 S = |A × B /2| , 又 A × B = | i j | = (x1*y2) i- (x2*y1)j ; 所以 S = |((x1*y2) - (x2*y1))/2 |;
| x1 y1 |
| x2 y2 |
代码:
#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000000+10;
struct node
{
double x,y;
node(double tx=0 , double ty = 0)
{
x = tx;
y = ty;
}
node operator - (const node&b)const
{
return node(x-b.x,y-b.y);
}
double operator *(const node&b)const
{
return x*b.y-y*b.x;
}
}p[110];
int main()
{
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
for(int i = 0 ; i < n ; i++)
cin >> p[i].x >> p[i].y;
double minc = INF;
for(int i = 0 ; i < n ; i++)
for(int j = i+1 ; j < n ; j++)
for(int k = j+1 ; k < n ; k++)
{
double area = fabs(((p[i]-p[k])*(p[i]-p[j]))/2.0);
if(area < 1e-10)
continue;
minc = min(minc,area);
}
if(minc == INF)
cout << "Impossible" << endl;
else
printf("%.2lf\n",minc);
}
return 0;
}
题意:给N个长度为5的16进制数,两两之间求异或并记录结果中1的个数,输出最小个数
思路:基本知识:十六进制的每一位可以转化成对应10进制数的四位二进制,如A = 10 = 1010等。这样我们可以进行这样一个预处理:记cmp[i][j]是i和j异或结果中1的个数,这样对于每一组,我们只需for(i,0,5)枚举每一位就可以了。但本题难点是数据量有100000,实在太大,就在这卡了好久………………结果网上搜解题报告,搜出来却是用随机数来定位…………当时心中一万个草泥马啊!!!果然小菜鸟阅历还是太少了。然后设定随机50W次后就华丽滴过了。。。。
代码:
#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 500000;
int cmp[16][16];
string hm[100000+10];
void mkCmp()
{
for(int i = 0 ; i < 16 ; i++)
for(int j = i ; j < 16 ; j++)
{
int tmp = i^j,cnt=0;
for(int k = 0 ; k < 4 ; k++)
if((1<<k) & tmp)
cnt++;
cmp[i][j] = cmp[j][i] = cnt;
}
}
int change(char a)
{
if(isalpha(a))
return a-'A'+10;
return a-'0';
}
int calc(int a , int b)
{
int ans=0;
for(int i = 0 ; i < 5 ; i++)
{
int x = change(hm[a][i]);
int y = change(hm[b][i]);
ans += cmp[x][y];
}
return ans;
}
int main()
{
mkCmp();
int t;
cin >>t;
while(t--)
{
int n;
cin >> n;
for(int i = 0 ; i < n ; i++)
cin >> hm[i];
int minc = INF;
for(int i = 0 ; i < MAXN ; i++)
{
int a = rand()%n;
int b = rand()%n;
if(a == b) b = (b+1)%n;
minc = min(minc,calc(a,b));
}
cout << minc << endl;
}
return 0;
}
题意:给一棵树,要求最少 (剪掉几根边+加上几根边) 能形成一个环(环的定义是无分支的环链,即每个点的度是2)
思路:先通到树的最深处,然后往上处理,遇到度>=2的就减到二为止,根节点1减到1,这样每个点都是散的,当然有减就有加,剪一条边意味着最后一定会将这个边接到别的点上,再加上最后根节点与尾结点相连成环,最后需要(剪的边数*2+1)次操作,即答案,算贪心思想吧,证明无力。。。。。
注意:dfs用默认栈的话会爆,用"#pragma comment(linker, "/STACK:102400000,102400000")"自己创建更大的栈,新技能get√
代码:
是分析某位大神的代码写出来的,本人有想法但写不出来,智商捉急
#pragma comment(linker, "/STACK:102400000,102400000")
#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000000+100;
vector<int> G[MAXN];
int res;
bool dfs(int cur , int fa)
{
int cnt=0;
for(int i = 0 ; i < G[cur].size() ; i++) //记下在疯狂的剪边之后还有哪些点赖在父亲身上
{
int next = G[cur][i];
if(fa == next) continue; //如果是前驱就略过
if(dfs(next,cur))
cnt++;
}
if(cnt >= 2)
{
if(cur == 1) //注意剪的首先是父节点相连的那条边,否则算法不成立
res += cnt-2;
else
res += cnt-1;
return false; //父子边剪掉了,就不用计数了
}
return true;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i = 0 ; i <= n ;i++)
G[i].clear();
for(int i = 1 ; i < n ; i++ )
{
int a,b;
scanf("%d%d",&a,&b);
G[a].push_back(b); //不能确定谁是谁的前驱,所以索性构造双向边,深搜时不必担心无限循环,vector邻接表还需掌握
G[b].push_back(a);
}
res = 0;
dfs(1,-1);
printf("%d\n",res*2+1);
}
return 0;
}
4715 - Difference Between Primes
题意:输入一个数,输出两个素数,这两个素数a,b满足a-b == n ,且a是最小的
思路:构造素数表是一定的,用筛法,然后从小到大枚举比n大的素数,只要满足a-n是素数就可以了,水题
代码:
#include "iostream"
#include "cstring"
#include "algorithm"
#include "cmath"
#include "cstdio"
#include "sstream"
#include "queue"
#include "vector"
#include "string"
#include "stack"
#include "cstdlib"
#include "deque"
#include "fstream"
#include "map"
using namespace std;
typedef long long LL;
const int INF = 0x1fffffff;
const int MAXN = 1000000+10;
int tp[MAXN];
vector<int> prime;
int n;
void init()
{
tp[0]=tp[1]=1;
for(int i = 2 ;i < MAXN ; i++)
if(!tp[i])
for(int j = i+i ; j < MAXN ; j+=i)
tp[j] = 1;
for(int i = 0 ; i < MAXN ; i++)
if(!tp[i])
prime.push_back(i);
}
int main()
{
int t;
cin >>t;
init();
while(t--)
{
cin >> n;
int ok = 0;
for(int i = 0 ; i < prime.size() ; i++)
if(prime[i] > n && !tp[prime[i]-n])
{
ok = 1;
cout << prime[i] << ' ' << prime[i]-n << endl;
break;
}
if(!ok)
cout << "FAIL" << endl;
}
return 0;
}