求職算法例題

幾個關鍵的核心思想 例如
充分使用當前已知條件,去掉重複無用遍歷 遞歸-DP-回溯

遞歸

搜索時核心思想是枚舉回溯

DFS(Depth First Search)

//僞代碼
class dfs(狀態A){
   if(A不合法)return ERR;
   if(A==目標)return TAR;
   else dfs(A的子節點)}

N紅皇后問題

國際象棋,一個皇后對角線、同行、同列上都不能有其他皇后
用一個2n大小的數組存儲主副對角線和同列狀態
主對角線相同 有x+y相同 //state[1][x+y]都是同一對角線
副對角線相同 有x+n-y相同
在這裏插入圖片描述

int cnt = 0; //可行解的個數
int *pos = new int[n]; //記錄cur行紅皇后的位置
vector<vector<bool>> state(3,vector<bool>(2n,true));
//存儲狀態:true=可以放;false=不可以放;
//[0][j]=同列;[1][j]=主對角線;[2][j]=副對角線


void dfs(int cur){   //當前搜索的行
   if(cur==n){ //搜索到了第n+1行,即得到一種可能性
   for(int i=0;i<n;i++){
      for(int j=0;j<n;j++){
          if(pos[i]==j)cout<<'x'; //當前可行解當前行上紅皇后的位置
          else cout<<'o';   //不能放的位置
      }
      cout<<endl;
   }
   cnt++;
   }
   else{ //cur<n;沒有搜索到n+1行;搜索沒有結束
      for(int j=0;j<n;j++){     //列舉當前行的可能性
         if(state[0][j]&&state[1][cur+j]
         &&state[2][cur+n-j])    //同列、對角線沒有,可放
         
         state[0][j]=false;     //更新狀態
         state[1][cur+j]=false;
         state[2][cur+n-j]=false;
         
         pos[cur] = j;          //記錄當前行皇后的位置
         dfs(cur+1);            //搜索下一行的可能性
         
         state[0][j]=true;      //還原狀態,開始另一種可能性
         state[1][cur+j]=true;
         state[2][cur+n-j]=true;
      }
   }
}

24點

#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
bool dfs(float* a,int n,char *op) {
	if (n >= 3) {
		float tmp = a[0];
		for (int i = 0; i < 3; i++) {
			switch(op[i]){
			case'+':tmp += a[i + 1]; break;
			case'-':tmp -= a[i + 1]; break;
			case'*':tmp *= a[i + 1]; break;
			case'/':tmp /= a[i + 1]; break;
            }
		}
		cout << a[0]<<op[0]<< a[1]<<op[1]<< a[2]<<op[2]<< a[3]<<'='<<tmp<< endl;
		if (tmp == 24)
			return true;
		else 
			return false;
	}
	else {
		op[n] = '+';
		if(dfs(a, n + 1, op))return true;
		op[n] = '-';
		if (dfs(a, n + 1, op))return true;
		op[n] = '*';
		if (dfs(a, n + 1, op))return true;
		op[n] = '/';
		if (dfs(a, n + 1, op))return true;
		return false;
	}
}
int main() {
	float a[4] = { 0,0,0,0 };
	while (cin >> a[0])
	{
		for (int i = 1; i < 4; i++)
			cin >> a[i];
		float tmp = 0;
		for (int i=4;i>0;i--)
			for (int j = 1; j < i; j++) 
				if (a[j - 1] > a[j]) {
					tmp = a[j - 1];
					a[j - 1] = a[j];
					a[j] = tmp;
				}
		char op[3] = { '\0' };
		bool f = false;
		while (next_permutation(a, a + 4))
		{
			f = dfs(a, 0, op);
			if (f)break;
		}
		cout << (f ? "true" : "false") << endl;
	}
	return 0;
}

數獨

在存在多解的情況下,使用暴力枚舉很可能有 無法負擔 的時間代價
此時應該使用回溯,利用當前條件儘快排除不可能的當前分支狀況,找到一個可行方向
先判斷合不合理,再遞歸下去

#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

bool check(int (&a)[9][9], int pos)
{
 int r = pos / 9, c = pos % 9;
 int count[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 for (int i = 0; i < 9; i++)
 {
  if (a[r][i] != 0 && count[a[r][i]] != 0)
  {
   return false;
  }
  count[a[r][i]]++;
 }
 fill(count, count + 10, 0);
 for (int i = 0; i < 9; i++)
 {
  if (a[i][c] != 0 && count[a[i][c]] != 0)
  {
   return false;
  }
  count[a[i][c]]++;
 }
 fill(count, count + 10, 0);
 int ri = r / 3, ci = c / 3;
 for (int i = 0; i < 9; i++)
 {
  if (a[ri * 3 + i / 3][ci * 3 + i % 3] != 0 && count[a[ri * 3 + i / 3][ci * 3 + i % 3]] != 0)
  {
   return false;
  }
  count[a[ri * 3 + i / 3][ci * 3 + i % 3]]++;
 }

 return true;
}

bool backtrack(int (&a)[9][9], int pos)
{
 if (pos == 81)
 {
  for (int i = 0; i < 9; i++)
  {
   for (int j = 0; j < 9; j++)
   {
    cout << a[i][j];
   }
   cout << endl;
  }
  return true;
 }
 int r = pos / 9, c = pos % 9;
 if (a[r][c] != 0)
 {
  return backtrack(a, pos + 1);
 }
 for (int i = 1; i <= 9; i++)
 {
  a[r][c] = i;
  if (check(a, pos))
  {
   if (backtrack(a, pos + 1))
   {
    return true;
   }
  }
  a[r][c] = 0;
 }
 return false;
}

int main()
{
 int a[9][9];
 for (int i = 0; i < 9; i++)
 {
  for (int j = 0; j < 9; j++)
  {
   cin >> a[i][j];
  }
 }
 backtrack(a, 0);
 return 0;
}

BFS(Breadth First Search)

//僞代碼
class bfs(){
Q.push_back(head);  //一個隊列存儲每一層的兄弟節點
while(!Q.empty()){
   tmp=Q.front();
   Q.pop();
   if(tmp非法)continue;
   else if (tmp==目標)return TAR;
   else Q.push_back(tmp子節點);   
   }
} 

迷宮找出路(deque)

#include<iostream>
#include<vector>
#include<deque>
using namespace std;
int main() {
	int n = 0, m = 0, k = 0, x = 0, y = 0;
	cin >> n >> m >> k;
	vector<vector<int>> map(n, vector<int>(m, 0));
	vector<deque<int>>tmpx(2, deque<int>()), tmpy(2, deque<int>());
	int cur = 0,next = 1;
	for (int i = 0; i < k; i++) {
		cin >> x >> y;
		map[x][y] = 2; //障礙=2
	}
	tmpx[cur].push_back(0);
	tmpy[cur].push_back(0);
	int step = 0;
	bool find = false;
	while (!tmpx[0].empty() || !tmpx[1].empty()) {
		if ((tmpx[cur].front() != n - 1) || (tmpy[cur].front() != m - 1)) {
			map[tmpx[cur].front()][tmpy[cur].front()] = 1;//走過            //障礙=2  走過=1
			if (tmpx[cur].front() + 1 < n && map[tmpx[cur].front() + 1][tmpy[cur].front()] == 0) { //向下可行
				tmpx[next].push_back(tmpx[cur].front() + 1);
				tmpy[next].push_back(tmpy[cur].front());
			}
			if (tmpx[cur].front() - 1 >= 0 && map[tmpx[cur].front() - 1][tmpy[cur].front()] == 0) { //向上可行
				tmpx[next].push_back(tmpx[cur].front() - 1);
				tmpy[next].push_back(tmpy[cur].front());
			}
			if (tmpy[cur].front() - 1 >= 0 && map[tmpx[cur].front()][tmpy[cur].front() - 1] == 0) { //向左可行
				tmpx[next].push_back(tmpx[cur].front());
				tmpy[next].push_back(tmpy[cur].front() - 1);
			}
			if (tmpy[cur].front() + 1 < m && map[tmpx[cur].front()][tmpy[cur].front() + 1] == 0) { //向右可行
				tmpx[next].push_back(tmpx[cur].front());
				tmpy[next].push_back(tmpy[cur].front() + 1);
			}
			tmpx[cur].pop_front(); //去掉當前步
			tmpy[cur].pop_front(); 
			if(tmpx[cur].empty()) {//當前步探測完畢
				step++;
				int tmp = cur;
				cur = next;
				next = tmp;  
		    }
		}
		else
		{
			find = true;
			cout << step << endl;
			break;
		}
	}
	if (find == false)cout << 0 << endl;
	return 0;
}

動態規劃(DP)

DP可以看作是對遞歸枚舉的剪枝優化,從下至上只搜索可能的分支
需要滿足無後向性:之後的狀態並不影響之前的狀態

1.找狀態量
2.找狀態方程(大問題拆成小問題)
3.確定初始和邊界
4.確定順序

最長遞增子序列

Input:
[2,1,4,3,1,5,6],7
Output:
4
方法一: O(n2)
核心 if(A[j]<A[i])B[i]=max(B[i],B[j]+1);

class AscentSequence {
public:
    int findLongest(vector<int> A, int n) {
        // write code here
        int maxn=0;
        int* B=new int[n];
        for(int i=0;i<n;i++)B[i]=1;
        for(int i=0;i<n;i++){
            for(int j=0;j<i;j++){
                if(A[j]<A[i])B[i]=max(B[i],B[j]+1);
            }
            if(maxn<B[i])maxn=B[i];
        }
        return maxn;
    }
};

方法二:O(NlogN)
核心 B爲有序數列,存儲每個[]長度子序列中最後一位,B[findp(B, A[i], end)] = A[i]; 更新小於A[i]的最大的最後一位

int findp(int B[], int Ai, int end) {
	int start = 0, mid = 0;
	while (start < end) {
		mid = (start + end) / 2;
		if (B[mid] < Ai)start = mid + 1;
		else if (B[mid] > Ai)end = mid;
		else return mid;
	}
	if (end <= 0)return 0;
	else return end;
}
    int findLongest(vector<int> A, int n) {
    int* B = new int[n]();
        B[0]=A[0];
	int end = 0;
	for (int i = 0; i < n; i++) {
		if (B[end] < A[i]) 
			B[++end] = A[i];
		else if (B[end] > A[i])
			B[findp(B, A[i], end)] = A[i];
	}
	return end + 1;
    }

最長公共子序列

Input:
“1A2C3D4B56”, 10, “B1D23CA45B6A”, 12
Output:
6
在這裏插入圖片描述
A[i]與B[j]的重合,狀態改變,取決於A[i-1],B[j-1]的狀態

class LCS {
public:
    int findLCS(string A, int n, string B, int m) {
        // write code here
        int table[n + 1][m + 1];
         
        for(int i = 0;i <= n;++i)table[i][0] = 0;
        for(int i = 0;i <= m;++i)table[0][i] = 0;
         
        for(int i = 0;i < n;++i){
            for(int j = 0;j < m;++j){
                if(A[i] == B[j])
                    table[i + 1][j + 1] = table[i][j] + 1;
                else {
                    table[i + 1][j + 1] = max(table[i][j + 1],table[i + 1][j]);
                }
            }
        }
        return table[n][m];
    }

最小編輯代價

c0,c1,c2分別爲插入、刪除和修改操作的代價,求將A變爲B的最小代價
Input:
“abc”,3,“adc”,3,5,3,100
Output:
8
在這裏插入圖片描述
B[j] ⇐ A[i]刪除所有元素(i*c1) + 空字符插入元素到B[j](j*c0)
min(dp[i-1][j] + c1, dp[i][j-1] + c0)
A[i-1]=B[j-1] 則B[j]可以直接由A[i]‘改’+c2,或A[i]刪光+增添至B[j]即dp[i][j]

int findMinCost(string A, int n, string B, int m, int c0, int c1, int c2)
{
        vector<vector<int>> dp(n + 1, vector<int>(m + 1));
        for (int j = 0; j <= m; j++)
            dp[0][j] = j*c0;
        for (int i = 0;i <= n; i++)
            dp[i][0] = i*c1;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++){
                dp[i][j] = min(dp[i-1][j] + c1, dp[i][j-1] + c0);
                if (A[i-1] == B[j-1])
                    dp[i][j] = min(dp[i-1][j-1], dp[i][j]);
                else
                    dp[i][j] = min(dp[i-1][j-1] + c2, dp[i][j]);
            }
        return dp[n][m];
}

字符串交錯組成

C是否由A和B原序交錯組成
Input:
“ABC”,3,“12C”,3,“A12BCC”,6
Output:
true

bool chkMixture(string A, int n, string B, int m, string C, int v) {
        if(n+m!=v)return false;
        vector<vector<bool>> dp (n+1,vector<bool>(m+1,false));
        int a=0;
        int b=0;
        dp[0][0] = true;
        for(int i=0;i<v;i++){
            if(A[a] == C[i] && dp[a][b] == true){
                a++;
                dp[a][b] = true;
            }
            if(B[b] == C[i] && dp[a][b] == true){
                b++;
                dp[a][b] = true;
            }
        }
        return dp[n][m];
    }

存在多種可能性,驗證某狀態的可能性 ⇒ if(上一狀態==true&&當前狀態==true)DP[當前]=true;

最小起點代價

吉比特18年A卷
G社正在開發一個新的戰棋類遊戲,在這個遊戲中,角色只能向2個方向移動:右、下。移動需要消耗行動力,遊戲地圖上劃分M*N個格子,當角色移動到某個格子上時,行動力就會加上格子上的值K(-100~100),當行動力<=0時遊戲失敗,請問要從地圖左上角移動到地圖右下角至少需要多少起始行動力,注意(玩家初始化到起始的左上角格子時也需要消耗行動力

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main() {
	int m, n;
	cin >> m >> n;
	vector<vector<int>> cost(m + 1, vector<int>(n + 1, 0));
	vector<vector<int>> arr(m + 1, vector<int>(n + 1, -1000));
	arr[0][1] = arr[1][0] = 0;
	for (int i = 0; i < m; i++)
		for (int j = 0; j < n; j++)
			cin >> arr[i + 1][j + 1];
	for (int i = 1; i < m + 1; i++)
		for (int j = 1; j < n + 1; j++) {
			arr[i][j] = arr[i][j] + max(arr[i - 1][j], arr[i][j - 1]);
			if (max(arr[i - 1][j], arr[i][j - 1]) == arr[i - 1][j])
				if (arr[i][j] < cost[i - 1][j])cost[i][j] = arr[i][j];
				else cost[i][j] = cost[i - 1][j];
			else
				if (arr[i][j] < cost[i][j-1])cost[i][j] = arr[i][j];
				else cost[i][j] = cost[i][j-1];
		}
	cout << 1-cost[m][n];
	return 0;
}

揹包問題

01揹包

N件物品代價Ci價值Wi放入容量爲V 的揹包,將哪些物品裝入揹包可使價值總和最大
狀態轉移方程:
f[i,v]=max{f[i1,v],f(i1,vCi)+Wi}f[i,v]=max\{f[i-1,v],f(i-1,v-C_i)+W_i\}
在這裏插入圖片描述
轉換爲動態規劃

int f[I+1][V+1]={0};
int val[I+1]={0,...}; //價值
int cst[I+1]={0,...}; //代價
for(int v=0;v<V+1;v++)
   for(int i=0;i<I+1;i++)
   f[i][v]=0;
for(int i=0;i<I+1;i++)
   for(int v=0;v<V+1;v++){ 
      if(cst[i]>v) //放不下
         f[i][v]=f[i-1][v];
      else{
         f[i][v]=max(f[i-1][v-cst[i]]+val[i],f[i-1][v]);
         //  max(騰出cst[i]空間放下i獲得的最大收益,不放i的最大收益)
      }
   }
return f[I+1][V+1];

遞歸會出現重複的子問題,是一種暴力枚舉
而動態規劃使用數組記錄子問題的解,因此再次查詢時直接讀取,避免了再次搜索重複子問題
核心思想:不選(0)還是選(1)

恰好填充

要求正好填滿所有格子,對不能存在的狀態(空格子)賦懲罰項-\infty表示非法,使得
在這裏插入圖片描述

完全揹包問題

物品不限量可重複裝入
F(i,v)=max{F(i1,vkC1)+kWi}F(i,v)=max\{F(i-1,v-kC_1)+kW_i\} 此時每種情況還要嘗試k次重複裝入,複雜度爲
O(NVVci) O(NV\sum{\frac{V}{c_i}})
首先排除CjCiC_j\geq C_i && WjWiW_j\leq W_i這樣大又沒價值的物品
將每種物品增倍爲20Ci21Ci22Ci...2k1CiV2^0C_i,2^1C_i,2^2C_i... 2^{k-1}C_i \leq V 這k種物品

//小米筆試19-9-6
//小米之家多種商品不同價格不限量,花光N元,最多買幾件,最少買幾件?
//輸入產品種類數量 \n產品價格\n產品價格...\n 預算N
//輸出最多/最少件數,不湊整-1
//示例 
//2 
//500 
//1 
//1000
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//S2能否通過S1刪除得到
int main() {
	int n = 0, m = 0;
	cin >> n;
	vector<int> p(n, 0);
	for (int i = 0; i < n; i++)
		cin >> p[i];
	cin >> m;
	vector<int>c(1,0), v(1,0); //cost - value
	for(int i=0;i<n;i++)
		for (int k = 0; pow(2, k) * p[i] <= m; k++) {
			v.push_back(pow(2, k));
			c.push_back(pow(2, k) * p[i]);
		}
	//轉換爲01揹包問題
	vector<vector<unsigned int>> arr(c.size(), vector<unsigned int>(m+1, 0));
	for (int i = 1; i < m + 1; i++)
		arr[0][i] = 1000;  //空格懲罰項,求最少產品件數設爲正無窮
	for(int i=1;i<c.size();i++)
		for (int j = 1; j < m + 1; j++)
		{
			if (c[i] > j)arr[i][j] = arr[i - 1][j];
			else 
				arr[i][j] = min(arr[i-1][j], arr[i-1][j-c[i]]+v[i]);
		}
	//打印dp表格
	for (int i = 0; i < c.size(); i++) {
		for (int j = 0; j < m + 1; j++)
			cout<<arr[i][j]<<"\t";
		cout << endl;
	}
	if (arr[c.size() - 1][m] >= 1000)cout << -1;
	else cout<< arr[c.size() - 1][m];
	return 0;
}

在這裏插入圖片描述

其他例題

有序二維數組的查找

要完全利用題幹信息,arr[0][j]是第j列最小,arr[i][0]是第i行最小

棧的壓入、彈出序列

順序一致= { while(!原棧.empty())if(相等)出棧; if(臨時棧.empty())return true;else return false; }

華爲機試

輸入:3(A)  輸出:AAA
輸入:2(2{A}2[B])1(C) 輸出:AABBAABBC
不考慮非法輸入

// 2019.8.30 用時50min I'm so vegetable......
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int main() {
	string in,com;
	cin >> in;
	vector<int> bp, n;
	int i = 0;
	do{
		if (in[i] >= '0' && in[i] <= '9')
			n.push_back(in[i] - '0');
		else if (in[i] == '[' || in[i] == '{' || in[i] == '(') {
			com.push_back(in[i]);
			bp.push_back(i);
		}
		else if ((in[i] >= 'a' && in[i] <= 'z') || (in[i] >= 'A' && in[i] <= 'Z')) {
			cout << in[i];
		}
		else if ((in[i] == ']' && com.back() == '[') ||
			(in[i] == ')' && com.back() == '(') ||
			(in[i] == '}' && com.back() == '{')) {
			n.back()--;
			if (n.back() != 0)i = bp.back();
			else {
				bp.pop_back();
				com.pop_back();
				n.pop_back();
			}
		}
		i++;
	} while (i<=in.size()||!com.empty());
	return 0;
}

數組分割,最大和最小

原題 Leetcode 410
無後向性:
將 nums[0…i] 分成 j 份時得到當前分割數組最大和的最小值,後面怎麼分割不影響這個值
f[i][j] 定義爲將 nums[0…i] 分成 j 份時分割數組最大和的最小值

字符串匹配

BF(Brute-Force)
暴力枚舉 O(M*N)
回溯 i=(ij+1)+1i=(i-j+1)+1

int BF(string S,string P)
{
  int i=0,j=0;
  while(i<S.size()&&j<P.size())
  {
    if(s[i]==P[j]){++i;++j;}
    else {i=i-j+2;j=0;}
    if(j==P.size())return i-j+1;
  }
  return -1;
}

KMP(Knuth Morris Pratt)
本質:利用模式串P自身的(對稱)結構信息 + 比較過程中得到的信息 O(M+N)

int KMP(string S,string P)
{
   //prefix table
   vector<int> prefix(P.size(),0);
   prefix[0]=0;
   int len=0,i=0;
   
}

TopK

網易雷火

2019.9.15.14:00~18:00
第一題AC
N個矩形,排序
(寬W,高H),優先面積升序
再寬高比 min(WH,HW)min(\frac{W}{H},\frac{H}{W})降序
再W升序

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class sq
{
public:
    float w=0;
    float h=0;
    float s=0;
    float r=0;
    sq(float a,float b):w(a),h(b)
    {
        s=a*b;
        if(a!=0&&b!=0)
        {
            float r1=a/b,r2=b/a;
            r=min(r1,r2);
        }
        else
            r=0;
    }
};
void mysort(vector<sq> &sqs)
{
    for(int i=sqs.size()-1;i>=0;i--)
    for(int j=0;j<i;j++)
    {
       if(sqs[j].s>sqs[j+1].s)
          swap(sqs[j],sqs[j+1]);
       else if(sqs[j].s==sqs[j+1].s)
       {
           if(sqs[j].r<sqs[j+1].r)
             swap(sqs[j],sqs[j+1]);
           else if(sqs[j].r==sqs[j+1].r)
            {
                if(sqs[j].w>sqs[j+1].w)
                 swap(sqs[j],sqs[j+1]);
            }
       }
    }
}
int main()
{
  int n=0;
  cin>>n;
  vector<sq> sqs;
  
  for(int i=0;i<n;i++)
  {
      float a=0.0,b=0.0;
      cin>>a;
      cin>>b;
      sqs.push_back(sq(a,b));
  }
  mysort(sqs);
  for(int i=0;i<n;i++)
   cout<< sqs[i].w <<" "<<sqs[i].h<<" ";
  return 0;
}

第二題AC
在這裏插入圖片描述
輸入N頂點和M個三角形標號(a,b,c),法向量相反則反轉點序,最小編號最前

#include<iostream>
#include<vector>
#include<algorithm>
#include<deque>
using namespace std;
class tr
{
public:
    bool fine=false;
    deque<int> vt;
    deque<vector<int>>l;
    tr(int a,int b,int c):vt({a,b,c})
    {
        l.push_back({a,b});
        l.push_back({b,c});
        l.push_back({c,a});
    }
    void first_sort()
    {
        fine=true;
        int tmp=min(vt[0],vt[1]);
        tmp=min(tmp,vt[2]);
        while(tmp!=l.front()[0])
        {
            vector<int> tmpl=l.front();
            l.pop_front();
            l.push_back(tmpl);
            int tmpv=vt.front();
            vt.pop_front();
            vt.push_back(tmpv);
        }
    }
    static bool byside(tr &tr1,tr &tr2)
    {
       int vtcnt=0;
       for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
        if(tr1.vt[i]==tr2.vt[j])vtcnt++;
       if(vtcnt==2)
        return true;
       else 
        return false;
    }
    static void turn(tr &untr,tr &tr) //未排序,已排序
    {
        for(int i=0;i<3;i++)
         for(int j=0;j<3;j++)
         if(untr.l[i]==tr.l[j])
         {
           //相鄰邊同向,三角形異,則重排
           swap(untr.vt[0],untr.vt[2]);
           untr.l.clear();
           untr.l.push_back({untr.vt[0],untr.vt[1]});
           untr.l.push_back({untr.vt[1],untr.vt[2]});
           untr.l.push_back({untr.vt[2],untr.vt[0]});
           untr.first_sort(); //重排序
           untr.fine=true; 
           return;
         }
        //相鄰邊異向,三角形同向  
        untr.first_sort(); //重排序
        untr.fine=true; 
        return; 
    }
};
int main()
{
  int n=0,m=0;
  cin>>n>>m;
  vector<tr> trs;  
  deque<tr*> sch;
  for(int i=0;i<m;i++)
  {
      int a=0,b=0,c=0;
      cin>>a;
      cin>>b;
      cin>>c;
      trs.push_back(tr(a,b,c));
  }
  trs[0].first_sort();
  //for(int i=0;i<3;i++)
  //cout<<trs[0].l[i][0]<<trs[0].l[i][1]<<endl;
  sch.push_back(&trs[0]);
  while(!sch.empty())
  {
      deque<tr*> tmpsch=sch;
      sch.clear();
      for(int cnt=0;cnt<tmpsch.size();cnt++)
      for(int i=0;i<m;i++)
      {
          if(trs[i].fine==false
             &&tr::byside(trs[i],*tmpsch[cnt]))
          {
              tr::turn(trs[i],*tmpsch[cnt]);
              sch.push_back(&trs[i]);
          }  
      }
  }
  for(int i=0;i<m;i++)
   cout<< trs[i].vt[0] <<" "<<trs[i].vt[1]<<" "<<trs[i].vt[2]<<endl;
  return 0;
}

後面的輸出特殊情況能搶10~25%,沒搶
第三題看着像揹包
做第四題的時候交卷了,奇偶討論1~n\sqrt{n}
更正:看了大神的說法,第三題狀態壓縮dp,第四題歐拉序列。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章