Một dãy con gồm các phần tử liên tiếp nhau trong một dãy cho trước được gọi là đoạn. Cho dãy gồm N số tự nhiên. Tìm đoạn ngắn nhất có tổng các phần tử bằng giá trị K cho trước.
Dữ liệu vào: tệp văn bản TDOAN.INP
Dòng thứ nhất: hai số tự nhiên N và K, 1 N 2000.
Từ dòng thứ hai trở đi: các phần tử của dãy. Dữ liệu ra: tệp văn bản TDOAN.OUT
Chứa một dòng duy nhất gồm hai số tự nhiên d – chỉ số đầu đoạn và L – số phần tử trong đoạn (chiều dài đoạn). Nếu vô nghiệm thì ghi 0 0.
Trong các tệp, dữ liệu trên cùng dòng cách nhau qua dấu cách.
Thuật toán
Frank Gray là nhà vật lý học Mỹ làm nghiên cứu viên tại hãng Bell Labs với hàng loạt phát minh có giá trị được ứng dụng trong truyền hình, cơ học, điện tử và toán học. Năm 1947 Gray đăng ký bằng phát minh về mã nhị phân
phản hồi sau này được gọi là mã Gray.
TDOAN.INP TDOAN.OUT 21 17 21 17 0 2 3 2 10 1 5 5 6 12 20 30 14 8 0 11 0 6 0 0 5 16 3
Ta giải bằng kĩ thuật cửa sổ trượt như sau. Xét đoạn a[i..j] với tồng S = a[i] + a[i+1] + … + a[j], i j. Đoạn này được gọi là cửa sổ. Ta cho cửa sổ này trượt dần qua phải và xét ba tình huống sau đây.
1) (S = K): ta ghi nhận điểm đầu i và độ dài đoạn là ji+1. Nếu độ dài này nhỏ hơn độ dài LMin thì ta cập nhật lại các giá trị iMin và Lmin (thủ tục Update). Rồi tiếp tục xét cửa sổ mới là a[i+1..j] .
2) (S < K): Ta dịch đầu phải của cửa sổ từ j sang j+1, giữ nguyên đầu trái (thủ tục Right). 3) (S > K): Ta co đầu trái của cửa sổ từ i thành i+1 (thủ tục Left).
Ta đặt phần tử a[n+1] = 0 làm lính canh.
(**************************************** TONG DOAN - Doan ngan nhat TONG DOAN - Doan ngan nhat
co tong K ****************************************) program TDoan; uses crt; const mn = 2001; bl = #32; fn = 'TDOAN.INP'; gn = 'TDOAN.OUT'; type mw1 = array[0..mn] of word; var f,g: text;
n,k: word; a: mw1;
iMin, LMin: word; iLeft,iRight: word; sum: word;
procedure Doc; var i: word; begin
assign(f,fn); reset(f); readln(f,n, k); for i := 1 to n do read(f,a[i]);
close(f); end;
procedure Left; begin
sum := sum - a[iLeft]; iLeft := iLeft + 1; if (iLeft > iRight) then
begin iRight := iLeft; sum := a[iLeft]; end; end;
procedure Right;
begin iRight := iRight + 1; sum := sum + a[iRight]; end; procedure Update;
begin
if (LMin > iRight - iLeft + 1) then
begin iMin := iLeft; LMin := iRight - iLeft + 1; end; Left;
end;
procedure XuLi; begin
iLeft := 1; iRight := iLeft; LMin := n + 1; sum := a[1]; repeat
if (sum = k) then Update
else if (sum < k) then Right else { sum > k } Left; until (iRight > n);
if (LMin = n+1) then LMin := 0; end;
procedure Ghi; begin
assign(g,gn); rewrite(g); writeln(g,iMin,bl,LMin); close(g); end;
BEGIN
Doc; XuLi; ghi; END. // C# using System; using System.IO; using System.Collections; namespace SangTao2 { class TongDoan {
const string fn = "TDoan.inp"; const string gn = "TDoan.out";
static public int n; // n - so phan tu static public int k; // Tong can chon static public int sum; // tong hien co
static public int ileft, iright; // hai dau cua so static public int imin, lmin;
static public int [] a;
static void Main(string[] args) { Doc(); XuLi(); Ghi(); XemKetQua(); Console.WriteLine("\n Fini "); Console.ReadLine();
}
static public void XemKetQua() {
Console.WriteLine("\n Input: "+fn); Console.WriteLine(File.ReadAllText(fn)); Console.WriteLine("\n Output: "+gn); Console.WriteLine(File.ReadAllText(gn)); }
static public void XuLi(){ ileft = 0; iright = ileft;
sum = a[ileft]; lmin = n + 1; while (iright < n)
if (sum == k) Update();
else if (sum < k) Right(); else /* s > k */ Left(); ++imin;
}
static public void Update() { if (lmin > iright - ileft + 1)
{ imin = ileft; lmin = iright - ileft + 1; } Left();
}
static public void Left(){ sum -= a[ileft++]; if (ileft > iright)
{ iright = ileft; sum = a[ileft]; } }
static public void Right() { sum += a[++iright]; } static public void Doc(){
int[] v =
new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries), new Converter<string, int>(int.Parse)); int j = 0; n = v[j++]; k = v[j++];
a = new int[n + 1]; a[n] = 0;
for (int i = 0; i < n; ++i) a[i] = v[j++]; }
static public void Ghi() {
if (lmin == n + 1) File.WriteAllText(gn, "0"); else File.WriteAllText(gn,imin.ToString()+" "+lmin.ToString()); } } // TongDoan } // SangTao2