小小地记一下CTSC酱油赛可能得到的一些搞笑算法,提交答案题可以拿来乱搞一下
单纯形:
这是用来搞线性规划的一种神器,因为很多东西归约之后都可以用线性规划做,所以这个算法应用面还是比较广的吧
具体做法参考算导吧,讲的非常详细
这里记一些我的理解
核心操作是pivot(i, j)表示用j方程中i变量作为换出变量,j方程的松弛变量作为换入变量对所有方程“消一次”。
代码如下:
procedure pivot(i,j:longint); var k,l,p:longint; begin k:=b[i];b[i]:=b[j+n+1];b[j+n+1]:=k; z:=-1/a[j,i]; c[0]:=0; // you hua for l:=0 to n+1 do begin if abs(a[j,l])>e then begin inc(c[0]);c[c[0]]:=l; end; a[j,l]:=a[j,l]*z; end; a[j,i]:=-z; for k:=0 to t do if (k<>j)and(abs(a[k,i])>e) then begin z:=a[k,i]; for l:=1 to c[0] do a[k,c[l]]:=a[k,c[l]]+a[j,c[l]]*z; a[k,i]:=a[j,i]*z; //!! *z end; end; |
每次找个目标函数中系数为正的卡的最紧的变量去消
B数组表示每个变量现在“在哪里”
基本初始解不可行的解决办法:(有些方程的常数 < 0)
设置一个x0,并在每个方程后加一个x0,x0是基本变量(隐含x0 >= 0)
然后选一个常数负的最多的方程i,调用pivot(x0, i)一遍,然后就会发现所有的常数都正了!
接着,由于实际上x0不能对原线性规划造成影响,所以x0应该要 = 0,那就先弄一个目标函数为最大化 –x0即可,若最后的目标式最大化后的结果为0,那就对了,否则就无解
通过这样一个过程(先跑一遍线性规划),就能得到一组基本可行解,然后再该干嘛干嘛
本题的话,只要一组可行解就够了,所以只要这样就够了
另外,简单提一下元素不满足非负性限制的解决办法,就是将每个变量x1拆成两个,记为x1’和x1’’,原来的x1替换为x1’ – x1’’,同时规定x1’和x1’’都具有非负性限制,这样就是等价的转化了
主程序调用
j:=0; a[0,n+1]:=-1; for i:=1 to t do begin a[i,n+1]:=1; if a[i,0]<a[j,0] then j:=i; end; for i:=1 to n+t+1 do b[i]:=i; pivot(n+1,j); while true do begin for i:=1 to n+1 do if a[0,i]>e then break; if a[0,i]<e then break; z:=1e30; for j:=1 to t do if (a[j,i]<-e)and(-a[j,0]/a[j,i]<z) then begin z:=-a[j,0]/a[j,i];k:=j; end; if z>1e29 then break; pivot(i,k); end; // if abs(a[0,0])>e then writeln('fuckly!'); for i:=1 to t do if b[i+n+1]<=n then ans[b[i+n+1]]:=a[i,0]; for i:=1 to n do writeln(ans[i]:0:6); |
还有一些转化的技巧,算导上都讲的很好,这里不赘述了
模拟退火:
经典非完美算法,编程复杂度低,性价比很不错的算法
虽然这个算法基本上是乱来,但还是有几个技巧的
第一个是顾研牛论文里讲的,以e^(-估价函数改进量/温度)的概率接受较劣解,但这个不绝对,有的题可能直接不接受较劣解会比较好,这种情况下模拟退火退化为随机化调整
还有一个是在每个温度上枚举时,枚举的次数不一定是一个常数,可以是关于温度的函数,也可以设置一个“失败常数”,即只允许出现这个“失败常数次”较劣解
另外,就是利用linux系统能分屏工作的特点,早早地让一个退火程序一直跑着,然后在另一个工作区做别的题,骗分做题两不误
还有一点,温度每次缩多少是有讲究的
FFT:
O(nlogn)的高精乘法,需要用到一大堆数论知识,虽然这个算法本身在竞赛中可能不怎么会考,但涉及到的很多数论知识都还是有用的,比方说原根什么的
只是,这个算法我暂时还不会-_-!
ps:不知道北京有没有长沙热~