心情記錄
放假,去實驗室補題,大學長給了我信心!
每個人都有從弱變強的過程,我只付出了一個月出頭,只是很多人的1/36啊
加油↖(^ω^)↗
知識點補充
手動擴棧
#pragma comment(linker, "/STACK:1024000000,1024000000")
題目
HDU 6127 Hard challenge
題意
平面座標系,給出n個點,保證任意兩點的連線不過原點.
每一個點都有一個權值,兩點之間的線段的權值等於端點權值之積
問如果過原點做一條直線,直線穿過的線段的權值和最大是多少
解決
這道題我們卡住了,想到了要用極角排序來做,也想到了去枚舉每一個經過原點和點的直線,但是思路卡在了”如何表示偏差一點點”上面
//直線左側的點一定能和直線右側的點連成線段,那麼直線兩端任意兩點權值積的和,就是兩個區間權值和的積
//好像有點繞╮(╯▽╰)╭...
/*
p1 /
/ p3 p1(p3+p4)+p2(p3+p4)=(p1+p2)*(p3+p4)
p2 /
/ p4 手動繪圖 ∩_∩)O哈哈哈~
/
*/
- 容易知道,直線兩端任意兩點權值積的和,就是兩個區間權值和的積(代碼裏面畫了圖(想不到吧^_^))
- 首先按照極角對每個點進行排序
- 初始直線從y軸開始,把x>=0的點都加到右區間,x<0的點都加到左區間
- 直線逆時針旋轉,每旋轉到一個點,把這個點從它原來所在的區間裏面剔除掉,加到另一個去見裏面
- 保存最大值
#define rep(i,a,b) for(int i=a;i<(b);++i)
struct point
{
int x,y,val;
double angle;
}P[50005];
bool cmp(point p1,point p2)
{
return p1.angle<p2.angle;
}
int main()
{
int n,cases;
long long ans,lsum,rsum; //lsum和rsum不會爆int但是相乘會爆int
scanf("%d",&cases);
while(cases--)
{
scanf("%d",&n);
rep(i,0,n){
scanf("%d%d%d",&P[i].x,&P[i].y,&P[i].val);
if(P[i].x==0) //這裏對x=0進行特判,除數不能爲0
{
if(P[i].y>0) P[i].angle=PI/2.0;
else P[i].angle=-PI/2.0;
}
else P[i].angle=atan(P[i].y*1.0/P[i].x);
}
//rep(i,0,n) cout<<P[i].angle<<endl;
sort(P,P+n,cmp);
ans=1;
lsum=rsum=0;
//初始先以y軸對做表面進行劃分
rep(i,0,n){
if(P[i].x>=0) rsum+=P[i].val; //出現在y軸右側(包含y軸)的點全部添加到右區間
else lsum+=P[i].val;
}
//直線左側的點一定能和直線右側的點連成線段,那麼直線兩端任意兩點權值積的和,就是兩個區間權值和的積
//好像有點繞╮(╯▽╰)╭...
/*
p1 /
/ p3 p1(p3+p4)+p2(p3+p4)=(p1+p2)*(p3+p4)
p2 /
/ p4 手動繪圖 ∩_∩)O哈哈哈~
/
*/
ans=lsum*rsum;
rep(i,0,n){ //根據極角排序的順序,遍歷每一個點,然後把這個點從它之前所在的區間裏剔除加到另一個區間
if(P[i].x>=0) //原來在右區間,從右區間剔除
{
rsum-=P[i].val;
lsum+=P[i].val;
}
else //原來在左區間,從左區間剔除
{
rsum+=P[i].val;
lsum-=P[i].val;
}
ans=max(ans,lsum*rsum);
}
cout<<ans<<endl;
}
}
UVA_122 Trees on the level
題意
讓我們構建一棵樹,給出每一個節點是從根節點怎麼走才能走到.
比如(11,LL)就是根節點的左子樹的左子節點的位置權值爲11.然後讓給出這棵樹的先序遍歷結果.
如果出現下列情況,輸出”not complete”
- 重複賦值
- 沒有根節點
- 有節點沒有被賦值(子節點有賦值,但是本身卻沒有賦值的情況)
- 給出超過一個節點
解決
這個題的輸入比較坑啊,剛上來感覺解決不了…
看了紫書,參考了博客.
解決輸入
- 主函數中用一個大循環,一直循環創建一個bool readin()函數
- 當程序讀入EOF的時候返回false,主函數退出循環
- 當readin中讀入”()”,返回true,主函數繼續循環
C語言字符串的靈活性-可以把任意”指向字符的指針”當做是字符串,從該位置開始,直到字符’\0’
建樹
- 創建node結構體,包含指向左兒子和右兒子的指針
- 每次從根節點開始走,走到對應位置,對當前位置進行賦值
先序遍歷
先序遍歷=根節點+左兒子的先序+右兒子的先序
- 用一個vector來保存遍歷結果
- 根節點入隊
- 如果左兒子存在,左兒子入隊
- 如果右兒子存在,右兒子入隊
#include<bits/stdc++.h>
using namespace std;
#define de(x) cout << #x << "=" << x << endl
#define rep(i,a,b) for(int i=a;i<(b);++i)
struct node
{
bool have_value; //是否已經被賦值
int v;
node *left,*right;
node():have_value(false),left(NULL),right(NULL){}
};
node *root;
node *newnode(){return new node();} //new函數後面要加個括號
bool gg;
void addnode(int v,char *s)
{
int len=strlen(s);
node *u=root; //u從根節點開始走,直到目標節點
rep(i,0,len){
if(s[i]=='L')
{
if(u->left==NULL) u->left=newnode();
u=u->left;
continue;
}
if(s[i]=='R')
{
if(u->right==NULL) u->right=newnode();
u=u->right;
continue;
}
}
if(u->have_value){gg=true;return ;} //如果當前節點已經被賦值,gg
u->v=v;
u->have_value=true; //標記爲已賦值
}
void delete_tree(node *u)
{
if(u==NULL) return ;
delete_tree(u->left);
delete_tree(u->right);
delete u;
}
bool readin()
{
char str[270];
gg=false;
while(1)
{
if(scanf("%s",str)==EOF) return false; //程序讀到EOF
if(!strcmp(str,"()")) break;
int v;
//de(str);
sscanf(&str[1],"%d",&v); //ssanf的使用要頭文件sstream
//de(v);
addnode(v,strchr(str,',')+1); //strchr()返回字符串從左到右第一個字符‘,’的指針
}
return true;
}
vector<int> ans;
bool bfs()
{
ans.clear();
queue<node*> Q;
Q.push(root);
while(!Q.empty())
{
node *u=Q.front();Q.pop();
if(!u->have_value) {gg=true;return false;}
ans.push_back(u->v);
if(u->left!=NULL) Q.push(u->left);
if(u->right!=NULL) Q.push(u->right);
}
return true;
}
int main()
{
while(1)
{
delete_tree(root);
root=newnode();
if(!readin()) break; //程序讀到了EOF
if(!gg&&bfs())
{
for(int i=0;i<ans.size();i++)
printf("%d%c",ans[i],i+1==ans.size()?'\n':' ');
}
else puts("not complete");
}
}